/src/kilim/analysis/MethodWeaver.java

http://github.com/kilim/kilim · Java · 659 lines · 470 code · 67 blank · 122 comment · 110 complexity · 3cabb109e4b4290962edbd444d33468c MD5 · raw file

  1. /* Copyright (c) 2006, Sriram Srinivasan
  2. *
  3. * You may distribute this software under the terms of the license
  4. * specified in the file "License"
  5. */
  6. package kilim.analysis;
  7. import static kilim.Constants.D_FIBER_LAST_ARG;
  8. import static kilim.Constants.D_INT;
  9. import static kilim.Constants.D_VOID;
  10. import static kilim.Constants.FIBER_CLASS;
  11. import static kilim.Constants.TASK_CLASS;
  12. import static kilim.analysis.VMType.TOBJECT;
  13. import static kilim.analysis.VMType.loadVar;
  14. import static org.objectweb.asm.Opcodes.ALOAD;
  15. import static org.objectweb.asm.Opcodes.ASTORE;
  16. import static org.objectweb.asm.Opcodes.DUP;
  17. import static org.objectweb.asm.Opcodes.GETFIELD;
  18. import static org.objectweb.asm.Opcodes.GOTO;
  19. import static org.objectweb.asm.Opcodes.INVOKESTATIC;
  20. import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
  21. import static org.objectweb.asm.Opcodes.RETURN;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.ListIterator;
  25. import kilim.Constants;
  26. import kilim.mirrors.Detector;
  27. import org.objectweb.asm.AnnotationVisitor;
  28. import org.objectweb.asm.Attribute;
  29. import org.objectweb.asm.ClassVisitor;
  30. import org.objectweb.asm.Handle;
  31. import org.objectweb.asm.MethodVisitor;
  32. import org.objectweb.asm.Opcodes;
  33. import org.objectweb.asm.Type;
  34. import org.objectweb.asm.tree.AbstractInsnNode;
  35. import org.objectweb.asm.tree.AnnotationNode;
  36. import org.objectweb.asm.tree.InvokeDynamicInsnNode;
  37. import org.objectweb.asm.tree.LabelNode;
  38. import org.objectweb.asm.tree.LdcInsnNode;
  39. import org.objectweb.asm.tree.LocalVariableNode;
  40. import org.objectweb.asm.tree.LookupSwitchInsnNode;
  41. import org.objectweb.asm.tree.TableSwitchInsnNode;
  42. import org.objectweb.asm.tree.TryCatchBlockNode;
  43. /**
  44. * This class takes the basic blocks from a MethodFlow and generates
  45. * all the extra code to support continuations.
  46. */
  47. public class MethodWeaver {
  48. private ClassWeaver classWeaver;
  49. private MethodFlow methodFlow;
  50. private boolean isPausable;
  51. private int maxVars;
  52. private int maxStack;
  53. private boolean isSAM;
  54. /**
  55. * The last parameter to a pausable method is a Fiber ref. The rest of the
  56. * code doesn't know this because we do local surgery, and so is likely to
  57. * stomp on the corresponding local var. We need to save this in a slot
  58. * beyond (the original) maxLocals that is a safe haven for keeping the
  59. * fiberVar.
  60. */
  61. private int fiberVar;
  62. private int numWordsInSig;
  63. private ArrayList<CallWeaver> callWeavers = new ArrayList<CallWeaver>(5);
  64. private Detector detector;
  65. MethodWeaver(ClassWeaver cw, Detector detector, MethodFlow mf, boolean isSAM) {
  66. this.detector = detector;
  67. this.classWeaver = cw;
  68. this.methodFlow = mf;
  69. isPausable = mf.isPausable();
  70. fiberVar = methodFlow.maxLocals;
  71. maxVars = fiberVar + 1;
  72. maxStack = methodFlow.maxStack + 1; // plus Fiber
  73. this.isSAM = isSAM;
  74. if (!mf.isAbstract()) {
  75. createCallWeavers();
  76. }
  77. }
  78. public void accept(ClassVisitor cv) {
  79. MethodFlow mf = methodFlow;
  80. String[] exceptions = ClassWeaver.toStringArray(mf.exceptions);
  81. String desc = mf.desc;
  82. String sig = mf.signature;
  83. int access = mf.access;
  84. if (mf.isPausable()) {
  85. access &= ~Opcodes.ACC_VARARGS;
  86. if (!isSAM) {
  87. desc = desc.replace(")", D_FIBER_LAST_ARG);
  88. if (sig != null)
  89. sig = sig.replace(")", D_FIBER_LAST_ARG);
  90. }
  91. }
  92. MethodVisitor mv = cv.visitMethod(access, mf.name, desc, sig, exceptions);
  93. if (!mf.isAbstract()) {
  94. if (mf.needsWeaving()) {
  95. accept(mv);
  96. } else {
  97. mf.accept(mv);
  98. }
  99. } else {
  100. mf.accept(mv);
  101. }
  102. }
  103. void accept(MethodVisitor mv) {
  104. visitAttrs(mv);
  105. visitCode(mv);
  106. mv.visitEnd();
  107. }
  108. private void visitAttrs(MethodVisitor mv) {
  109. MethodFlow mf = methodFlow;
  110. // visits the method attributes
  111. int i, j, n;
  112. if (mf.annotationDefault != null) {
  113. AnnotationVisitor av = mv.visitAnnotationDefault();
  114. MethodFlow.acceptAnnotation(av, null, mf.annotationDefault);
  115. av.visitEnd();
  116. }
  117. n = mf.visibleAnnotations == null ? 0 : mf.visibleAnnotations.size();
  118. for (i = 0; i < n; ++i) {
  119. AnnotationNode an = (AnnotationNode) mf.visibleAnnotations.get(i);
  120. an.accept(mv.visitAnnotation(an.desc, true));
  121. }
  122. n = mf.invisibleAnnotations == null ? 0
  123. : mf.invisibleAnnotations.size();
  124. for (i = 0; i < n; ++i) {
  125. AnnotationNode an = (AnnotationNode) mf.invisibleAnnotations.get(i);
  126. an.accept(mv.visitAnnotation(an.desc, false));
  127. }
  128. n = mf.visibleParameterAnnotations == null ? 0
  129. : mf.visibleParameterAnnotations.length;
  130. for (i = 0; i < n; ++i) {
  131. List<?> l = mf.visibleParameterAnnotations[i];
  132. if (l == null) {
  133. continue;
  134. }
  135. for (j = 0; j < l.size(); ++j) {
  136. AnnotationNode an = (AnnotationNode) l.get(j);
  137. an.accept(mv.visitParameterAnnotation(i, an.desc, true));
  138. }
  139. }
  140. n = mf.invisibleParameterAnnotations == null ? 0
  141. : mf.invisibleParameterAnnotations.length;
  142. for (i = 0; i < n; ++i) {
  143. List<?> l = mf.invisibleParameterAnnotations[i];
  144. if (l == null) {
  145. continue;
  146. }
  147. for (j = 0; j < l.size(); ++j) {
  148. AnnotationNode an = (AnnotationNode) l.get(j);
  149. an.accept(mv.visitParameterAnnotation(i, an.desc, false));
  150. }
  151. }
  152. n = mf.attrs == null ? 0 : mf.attrs.size();
  153. for (i = 0; i < n; ++i) {
  154. mv.visitAttribute((Attribute) mf.attrs.get(i));
  155. }
  156. }
  157. private void visitCode(MethodVisitor mv) {
  158. mv.visitCode();
  159. methodFlow.resetLabels();
  160. visitTryCatchBlocks(mv);
  161. visitInstructions(mv);
  162. visitLocals(mv);
  163. visitLineNumbers(mv);
  164. mv.visitMaxs(maxStack, maxVars);
  165. }
  166. private void visitLineNumbers(MethodVisitor mv) {
  167. methodFlow.visitLineNumbers(mv);
  168. }
  169. private void visitLocals(MethodVisitor mv) {
  170. for (Object l: methodFlow.localVariables) {
  171. ((LocalVariableNode)l).accept(mv);
  172. }
  173. }
  174. private void visitInstructions(MethodVisitor mv) {
  175. MethodFlow mf = methodFlow;
  176. genPrelude(mv);
  177. BasicBlock lastBB = null;
  178. boolean dsl = dslName.equals(mf.name) & dslDesc.equals(mf.desc);
  179. if (dsl)
  180. preweaveDeserializeLambda();
  181. for (BasicBlock bb : mf.getBasicBlocks()) {
  182. int from = bb.startPos;
  183. if (bb.isPausable() && bb.startFrame != null) {
  184. genPausableMethod(mv, bb);
  185. from = bb.startPos + 1; // first instruction is consumed
  186. } else if (bb.isCatchHandler()) {
  187. List<CallWeaver> cwList = getCallsUnderCatchBlock(bb);
  188. if (cwList != null) {
  189. genException(mv, bb, cwList);
  190. from = bb.startPos + 1; // first instruction is consumed
  191. } // else no different from any other block
  192. }
  193. int to = bb.endPos;
  194. for (int i = from; i <= to; i++) {
  195. LabelNode l = mf.getLabelAt(i);
  196. if (l != null) {
  197. l.accept(mv);
  198. }
  199. AbstractInsnNode ain = bb.getInstruction(i);
  200. if (ain.getOpcode() == Constants.INVOKEDYNAMIC) {
  201. transformIndyBootstrap(mv, ain);
  202. } else {
  203. ain.accept(mv);
  204. }
  205. }
  206. lastBB = bb;
  207. }
  208. if (lastBB != null) {
  209. LabelNode l = methodFlow.getLabelAt(lastBB.endPos+1);
  210. if (l != null) {
  211. l.accept(mv);
  212. }
  213. }
  214. }
  215. static String dslName = "$deserializeLambda$";
  216. static String dslDesc = "(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;";
  217. private static String addFiber(String type) {
  218. return type.replace(")", Constants.D_FIBER_LAST_ARG);
  219. }
  220. /**
  221. * at least with openjdk 8-11, deserializing lambdas checks the signature or the target.
  222. * FIXME: this method is implementation dependent (probably unfixable, but want this line to show in a grep)
  223. */
  224. public void preweaveDeserializeLambda() {
  225. int maxState = 22;
  226. int state = 0;
  227. String cname = null;
  228. String mname = null;
  229. int num = methodFlow.instructions.size();
  230. for (int ii=0; ii < num; ii++) {
  231. AbstractInsnNode node = methodFlow.instructions.get(ii);
  232. int opcode = node.getOpcode();
  233. if (opcode != Opcodes.LDC) {
  234. if (opcode==Opcodes.INVOKEDYNAMIC || opcode==Opcodes.LOOKUPSWITCH)
  235. state = 0;
  236. continue;
  237. }
  238. LdcInsnNode ldc = (LdcInsnNode) node;
  239. switch (state) {
  240. case 0: cname = (String) ldc.cst; break;
  241. case 1: mname = (String) ldc.cst; break;
  242. case 2:
  243. String mdesc = (String) ldc.cst;
  244. if (detector.getPausableStatus(cname,mname,mdesc)==Detector.PAUSABLE_METHOD_FOUND)
  245. ldc.cst = addFiber(mdesc);
  246. else
  247. state = maxState;
  248. break;
  249. case 4: ldc.cst = addFiber((String) ldc.cst); break;
  250. }
  251. state++;
  252. }
  253. }
  254. private void transformIndyBootstrap(MethodVisitor mv, AbstractInsnNode ain) {
  255. InvokeDynamicInsnNode indy = (InvokeDynamicInsnNode)ain;
  256. Object[]bsmArgs = indy.bsmArgs;
  257. // Is it a lambda conversion
  258. if (indy.bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")) {
  259. Handle lambdaBody = (Handle)bsmArgs[1];
  260. String desc = lambdaBody.getDesc();
  261. if (detector.isPausable(lambdaBody.getOwner(), lambdaBody.getName(), desc)) {
  262. bsmArgs[0] = addFiberType((Type)bsmArgs[0]);
  263. bsmArgs[1] = new Handle(lambdaBody.getTag(),
  264. lambdaBody.getOwner(),
  265. lambdaBody.getName(),
  266. desc.replace(")", D_FIBER_LAST_ARG),
  267. lambdaBody.isInterface());
  268. bsmArgs[2] = addFiberType((Type)bsmArgs[2]);
  269. }
  270. }
  271. ain.accept(mv);
  272. }
  273. private static Type addFiberType(Type type) {
  274. String typeDesc = type.toString().replace(")", D_FIBER_LAST_ARG);
  275. return Type.getType(typeDesc);
  276. }
  277. private List<CallWeaver> getCallsUnderCatchBlock(BasicBlock catchBB) {
  278. List<CallWeaver> cwList = null; // create it lazily
  279. for (CallWeaver cw: callWeavers) {
  280. for (Handler h: cw.bb.handlers) {
  281. if (h.catchBB == catchBB) {
  282. if (cwList == null) {
  283. cwList = new ArrayList<CallWeaver>(callWeavers.size());
  284. }
  285. if (!cwList.contains(cw)) {
  286. cwList.add(cw);
  287. }
  288. }
  289. }
  290. }
  291. return cwList;
  292. }
  293. /**
  294. * For a method invocation f(...), this method assumes that the arguments to
  295. * the call have already been pushed in. We need to push in the Fiber as the
  296. * final argument, make the call, then add the code for post-calls, then
  297. * leave it to visitInstructions() to resume visiting the remaining
  298. * instructions in the block
  299. *
  300. * <pre>
  301. * F_CALL:
  302. * aload &lt;fiberVar&gt;
  303. * invokevirtual fiber.down() ;; returns Fiber
  304. * ... invoke ....
  305. * aload &lt;fiberVar&gt;
  306. * ... post call code
  307. * F_RESUME:
  308. * </pre>
  309. *
  310. * @param bb
  311. * The BasicBlock that contains the pausable method invocation as the first
  312. * instruction
  313. * @param mv
  314. */
  315. private void genPausableMethod(MethodVisitor mv, BasicBlock bb) {
  316. CallWeaver caw = null;
  317. if (bb.isGetCurrentTask()) {
  318. genGetCurrentTask(mv, bb);
  319. return;
  320. }
  321. for (CallWeaver cw : callWeavers) {
  322. if (cw.getBasicBlock() == bb) {
  323. caw = cw;
  324. break;
  325. }
  326. }
  327. caw.genCall(mv);
  328. caw.genPostCall(mv);
  329. }
  330. /*
  331. * The Task.getCurrentTask() method is marked pausable to force
  332. * the caller to be pausable too. But the method doesn't really
  333. * pause; it merely looks up the task from the fiber. This is a
  334. * special case where the call to getCurrentTask is replaced by
  335. * <pre>
  336. * load fiberVar
  337. * getfield task
  338. * @param mv
  339. */
  340. void genGetCurrentTask(MethodVisitor mv, BasicBlock bb) {
  341. bb.startLabel.accept(mv);
  342. loadVar(mv, TOBJECT, getFiberVar());
  343. mv.visitFieldInsn(GETFIELD, FIBER_CLASS, "task", Constants.D_TASK);
  344. }
  345. private boolean hasGetCurrentTask() {
  346. MethodFlow mf = methodFlow;
  347. for (BasicBlock bb : mf.getBasicBlocks()) {
  348. if (!bb.isPausable() || bb.startFrame==null) continue;
  349. if (bb.isGetCurrentTask()) return true;
  350. }
  351. return false;
  352. }
  353. private void createCallWeavers() {
  354. MethodFlow mf = methodFlow;
  355. for (BasicBlock bb : mf.getBasicBlocks()) {
  356. if (!bb.isPausable() || bb.startFrame==null) continue;
  357. // No prelude needed for Task.getCurrentTask().
  358. if (bb.isGetCurrentTask()) continue;
  359. CallWeaver cw = new CallWeaver(this, detector, bb);
  360. callWeavers.add(cw);
  361. }
  362. }
  363. /**
  364. *
  365. * Say there are two invocations to two pausable methods obj.f(int)
  366. * (virtual) and fs(double) (a static call) ; load fiber from last arg, and
  367. * save it in a fresh register ; lest it gets stomped on. This is because we
  368. * only patch locally, and don't change the other instructions.
  369. *
  370. * <pre>
  371. * aload lastVar
  372. * dup
  373. * astore fiberVar
  374. * switch (fiber.pc) {
  375. * default: 0: START
  376. * 1: F_PASS_DOWN
  377. * 2: FS_PASS_DOWN
  378. * }
  379. * </pre>
  380. */
  381. private void genPrelude(MethodVisitor mv) {
  382. if (!methodFlow.isPausable()) return;
  383. if (callWeavers.size() == 0 && (!hasGetCurrentTask())) {
  384. // Method has been marked pausable, but does not call any pausable methods, nor Task.getCurrentTask.
  385. // Prelude is not needed at all.
  386. return;
  387. }
  388. MethodFlow mf = methodFlow;
  389. // load fiber from last var
  390. int lastVar = getFiberArgVar();
  391. mv.visitVarInsn(ALOAD, lastVar);
  392. if (lastVar < fiberVar) {
  393. if (callWeavers.size() > 0) {
  394. mv.visitInsn(DUP); // for storing into fiberVar
  395. }
  396. mv.visitVarInsn(ASTORE, getFiberVar());
  397. }
  398. if (callWeavers.size() == 0) {
  399. // No pausable method calls, but Task.getCurrentTask() is present.
  400. // We don't need the rest of the prelude.
  401. return;
  402. }
  403. mv.visitFieldInsn(GETFIELD, FIBER_CLASS, "pc", D_INT);
  404. // The prelude doesn't need more than two words in the stack.
  405. // The callweaver gen* methods may need more.
  406. ensureMaxStack(2);
  407. // switch stmt
  408. LabelNode startLabel = mf.getOrCreateLabelAtPos(0);
  409. LabelNode errLabel = new LabelNode();
  410. LabelNode[] labels = new LabelNode[callWeavers.size() + 1];
  411. labels[0] = startLabel;
  412. for (int i = 0; i < callWeavers.size(); i++) {
  413. labels[i + 1] = new LabelNode();
  414. }
  415. new TableSwitchInsnNode(0, callWeavers.size(), errLabel, labels).accept(mv);
  416. errLabel.accept(mv);
  417. mv.visitVarInsn(ALOAD, getFiberVar());
  418. mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "wrongPC", "()V", false);
  419. // Generate pass through down code, one for each pausable method
  420. // invocation
  421. int last = callWeavers.size() - 1;
  422. for (int i = 0; i <= last; i++) {
  423. CallWeaver cw = callWeavers.get(i);
  424. labels[i+1].accept(mv);
  425. cw.genRewind(mv);
  426. }
  427. startLabel.accept(mv);
  428. }
  429. boolean isStatic() {
  430. return methodFlow.isStatic();
  431. }
  432. int getFiberArgVar() {
  433. int lastVar = getNumWordsInSig();
  434. if (!isStatic()) {
  435. lastVar++;
  436. }
  437. return lastVar;
  438. }
  439. /*
  440. * The number of words in the argument; doubles/longs occupy
  441. * two local vars.
  442. */
  443. int getNumWordsInSig() {
  444. if (numWordsInSig != -1) {
  445. String[]args = TypeDesc.getArgumentTypes(methodFlow.desc);
  446. int size = 0;
  447. for (int i = 0; i < args.length; i++) {
  448. size += TypeDesc.isDoubleWord(args[i]) ? 2 : 1;
  449. }
  450. numWordsInSig = size;
  451. }
  452. return numWordsInSig;
  453. }
  454. /**
  455. * Generate code for only those catch blocks that are reachable
  456. * from one or more pausable blocks. fiber.pc tells us which
  457. * nested call possibly caused an exception, fiber.status tells us
  458. * whether there is any state that needs to be restored, and
  459. * fiber.curState gives us access to that state.
  460. *
  461. * ; Figure out which pausable method could have caused this.
  462. *
  463. * switch (fiber.upEx()) {
  464. * 0: goto NORMAL_EXCEPTION_HANDLING;
  465. * 2: goto RESTORE_F
  466. * }
  467. * RESTORE_F:
  468. * if (fiber.curStatus == HAS_STATE) {
  469. * restore variables from the state. don't restore stack
  470. * goto NORMAL_EXCEPTION_HANDLING
  471. * }
  472. * ... other RESTOREs
  473. *
  474. * NORMAL_EXCEPTION_HANDLING:
  475. */
  476. private void genException(MethodVisitor mv, BasicBlock bb, List<CallWeaver> cwList) {
  477. bb.startLabel.accept(mv);
  478. LabelNode resumeLabel = new LabelNode();
  479. VMType.loadVar(mv, VMType.TOBJECT, getFiberVar());
  480. mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "upEx", "()I", false);
  481. // fiber.pc is on stack
  482. LabelNode[] labels = new LabelNode[cwList.size()];
  483. int[] keys = new int[cwList.size()];
  484. for (int i = 0; i < cwList.size(); i++) {
  485. labels[i] = new LabelNode();
  486. keys[i] = callWeavers.indexOf(cwList.get(i)) + 1;
  487. }
  488. new LookupSwitchInsnNode(resumeLabel, keys, labels).accept(mv);
  489. int i = 0;
  490. for (CallWeaver cw: cwList) {
  491. if (i > 0) {
  492. // This is the jump (to normal exception handling) for the previous
  493. // switch case.
  494. mv.visitJumpInsn(GOTO, resumeLabel.getLabel());
  495. }
  496. labels[i].accept(mv);
  497. cw.genRestoreEx(mv, labels[i]);
  498. i++;
  499. }
  500. // Consume the first instruction because we have already consumed the
  501. // corresponding label. (The standard visitInstructions code does a
  502. // visitLabel before visiting the instruction itself)
  503. resumeLabel.accept(mv);
  504. bb.getInstruction(bb.startPos).accept(mv);
  505. }
  506. int getFiberVar() {
  507. return fiberVar; // The first available slot
  508. }
  509. void visitTryCatchBlocks(MethodVisitor mv) {
  510. MethodFlow mf = methodFlow;
  511. ArrayList<BasicBlock> bbs = mf.getBasicBlocks();
  512. ArrayList<Handler> allHandlers = new ArrayList<Handler>(bbs.size() * 2);
  513. for (BasicBlock bb : bbs) {
  514. allHandlers.addAll(bb.handlers);
  515. }
  516. allHandlers = Handler.consolidate(allHandlers);
  517. for (Handler h : allHandlers) {
  518. new TryCatchBlockNode(mf.getLabelAt(h.from), mf.getOrCreateLabelAtPos(h.to+1), h.catchBB.startLabel, h.type).accept(mv);
  519. }
  520. }
  521. void ensureMaxVars(int numVars) {
  522. if (numVars > maxVars) {
  523. maxVars = numVars;
  524. }
  525. }
  526. void ensureMaxStack(int numStack) {
  527. if (numStack > maxStack) {
  528. maxStack = numStack;
  529. }
  530. }
  531. int getPC(CallWeaver weaver) {
  532. for (int i = 0; i < callWeavers.size(); i++) {
  533. if (callWeavers.get(i) == weaver)
  534. return i + 1;
  535. }
  536. assert false : " No weaver found";
  537. return 0;
  538. }
  539. public String createStateClass(ValInfoList valInfoList) {
  540. return classWeaver.createStateClass(valInfoList);
  541. }
  542. void makeNotWovenMethod(ClassVisitor cv, MethodFlow mf, boolean isSAM) {
  543. if (classWeaver.classFlow.isJava7() && classWeaver.isInterface()) {
  544. MethodVisitor mv = cv.visitMethod(mf.access, mf.name, mf.desc,
  545. mf.signature, ClassWeaver.toStringArray(mf.exceptions));
  546. visitAttrs(mv);
  547. mv.visitEnd();
  548. } else {
  549. // Turn of abstract modifier
  550. int access = mf.access;
  551. access &= ~Constants.ACC_ABSTRACT;
  552. String desc = isSAM ? mf.desc.replace(")", Constants.D_FIBER_LAST_ARG) : mf.desc;
  553. MethodVisitor mv = cv.visitMethod(access, mf.name, desc,
  554. mf.signature, ClassWeaver.toStringArray(mf.exceptions));
  555. mv.visitCode();
  556. visitAttrs(mv);
  557. boolean isInterface = classWeaver.isInterface() && !isSAM;
  558. mv.visitMethodInsn(INVOKESTATIC, TASK_CLASS, "errNotWoven", "()V", isInterface);
  559. String rdesc = TypeDesc.getReturnTypeDesc(mf.desc);
  560. // stack size depends on return type, because we want to load
  561. // a constant of the appropriate size on the stack for
  562. // the corresponding xreturn instruction.
  563. int stacksize = 0;
  564. if (rdesc != D_VOID) {
  565. // ICONST_0; IRETURN or ACONST_NULL; ARETURN etc.
  566. stacksize = TypeDesc.isDoubleWord(rdesc) ? 2 : 1;
  567. int vmt = VMType.toVmType(rdesc);
  568. mv.visitInsn(VMType.constInsn[vmt]);
  569. mv.visitInsn(VMType.retInsn[vmt]);
  570. } else {
  571. mv.visitInsn(RETURN);
  572. }
  573. int numlocals;
  574. if ((mf.access & Constants.ACC_ABSTRACT) != 0) {
  575. // The abstract method doesn't contain the number of locals required to hold the
  576. // args, so we need to calculate it.
  577. numlocals = getNumWordsInSig() + 1 /* fiber */;
  578. if (!mf.isStatic()) numlocals++;
  579. } else {
  580. numlocals = mf.maxLocals + 1;
  581. }
  582. mv.visitMaxs(stacksize, numlocals);
  583. mv.visitEnd();
  584. }
  585. }
  586. ClassWeaver getClassWeaver() {
  587. return this.classWeaver;
  588. }
  589. MethodFlow getMethodFlow() {
  590. return this.methodFlow;
  591. }
  592. }