1. package com.sun.org.apache.bcel.internal.verifier.structurals;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import com.sun.org.apache.bcel.internal.generic.*;
  56. import com.sun.org.apache.bcel.internal.verifier.exc.*;
  57. import java.awt.Color;
  58. import java.util.ArrayList;
  59. import java.util.Enumeration;
  60. import java.util.HashSet;
  61. import java.util.Hashtable;
  62. import java.util.Iterator;
  63. /**
  64. * Instances of this class contain information about the subroutines
  65. * found in a code array of a method.
  66. * This implementation considers the top-level (the instructions
  67. * reachable without a JSR or JSR_W starting off from the first
  68. * instruction in a code array of a method) being a special subroutine;
  69. * see getTopLevel() for that.
  70. * Please note that the definition of subroutines in the Java Virtual
  71. * Machine Specification, Second Edition is somewhat incomplete.
  72. * Therefore, JustIce uses an own, more rigid notion.
  73. * Basically, a subroutine is a piece of code that starts at the target
  74. * of a JSR of JSR_W instruction and ends at a corresponding RET
  75. * instruction. Note also that the control flow of a subroutine
  76. * may be complex and non-linear; and that subroutines may be nested.
  77. * JustIce also mandates subroutines not to be protected by exception
  78. * handling code (for the sake of control flow predictability).
  79. * To understand JustIce's notion of subroutines, please read
  80. *
  81. * TODO: refer to the paper.
  82. *
  83. * @version $Id: Subroutines.java,v 1.1.1.1 2001/10/29 20:00:42 jvanzyl Exp $
  84. * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
  85. * @see #getTopLevel()
  86. */
  87. public class Subroutines{
  88. /**
  89. * This inner class implements the Subroutine interface.
  90. */
  91. private class SubroutineImpl implements Subroutine{
  92. /**
  93. * UNSET, a symbol for an uninitialized localVariable
  94. * field. This is used for the "top-level" Subroutine;
  95. * i.e. no subroutine.
  96. */
  97. private final int UNSET = -1;
  98. /**
  99. * The Local Variable slot where the first
  100. * instruction of this subroutine (an ASTORE) stores
  101. * the JsrInstruction's ReturnAddress in and
  102. * the RET of this subroutine operates on.
  103. */
  104. private int localVariable = UNSET;
  105. /** The instructions that belong to this subroutine. */
  106. private HashSet instructions = new HashSet(); // Elements: InstructionHandle
  107. /*
  108. * Refer to the Subroutine interface for documentation.
  109. */
  110. public boolean contains(InstructionHandle inst){
  111. return instructions.contains(inst);
  112. }
  113. /**
  114. * The JSR or JSR_W instructions that define this
  115. * subroutine by targeting it.
  116. */
  117. private HashSet theJSRs = new HashSet();
  118. /**
  119. * The RET instruction that leaves this subroutine.
  120. */
  121. private InstructionHandle theRET;
  122. /**
  123. * Returns a String representation of this object, merely
  124. * for debugging purposes.
  125. * (Internal) Warning: Verbosity on a problematic subroutine may cause
  126. * stack overflow errors due to recursive subSubs() calls.
  127. * Don't use this, then.
  128. */
  129. public String toString(){
  130. String ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'.";
  131. ret += " Accessed local variable slots: '";
  132. int[] alv = getAccessedLocalsIndices();
  133. for (int i=0; i<alv.length; i++){
  134. ret += alv[i]+" ";
  135. }
  136. ret+="'.";
  137. ret += " Recursively (via subsub...routines) accessed local variable slots: '";
  138. alv = getRecursivelyAccessedLocalsIndices();
  139. for (int i=0; i<alv.length; i++){
  140. ret += alv[i]+" ";
  141. }
  142. ret+="'.";
  143. return ret;
  144. }
  145. /**
  146. * Sets the leaving RET instruction. Must be invoked after all instructions are added.
  147. * Must not be invoked for top-level 'subroutine'.
  148. */
  149. void setLeavingRET(){
  150. if (localVariable == UNSET){
  151. throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
  152. }
  153. Iterator iter = instructions.iterator();
  154. InstructionHandle ret = null;
  155. while(iter.hasNext()){
  156. InstructionHandle actual = (InstructionHandle) iter.next();
  157. if (actual.getInstruction() instanceof RET){
  158. if (ret != null){
  159. throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'.");
  160. }
  161. else{
  162. ret = actual;
  163. }
  164. }
  165. }
  166. if (ret == null){
  167. throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
  168. }
  169. if (((RET) ret.getInstruction()).getIndex() != localVariable){
  170. throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'.");
  171. }
  172. theRET = ret;
  173. }
  174. /*
  175. * Refer to the Subroutine interface for documentation.
  176. */
  177. public InstructionHandle[] getEnteringJsrInstructions(){
  178. if (this == TOPLEVEL) {
  179. throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
  180. }
  181. InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()];
  182. return (InstructionHandle[]) (theJSRs.toArray(jsrs));
  183. }
  184. /**
  185. * Adds a new JSR or JSR_W that has this subroutine as its target.
  186. */
  187. public void addEnteringJsrInstruction(InstructionHandle jsrInst){
  188. if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){
  189. throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
  190. }
  191. if (localVariable == UNSET){
  192. throw new AssertionViolatedException("Set the localVariable first!");
  193. }
  194. else{
  195. // Something is wrong when an ASTORE is targeted that does not operate on the same local variable than the rest of the
  196. // JsrInstruction-targets and the RET.
  197. // (We don't know out leader here so we cannot check if we're really targeted!)
  198. if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){
  199. throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
  200. }
  201. }
  202. theJSRs.add(jsrInst);
  203. }
  204. /*
  205. * Refer to the Subroutine interface for documentation.
  206. */
  207. public InstructionHandle getLeavingRET(){
  208. if (this == TOPLEVEL) {
  209. throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
  210. }
  211. return theRET;
  212. }
  213. /*
  214. * Refer to the Subroutine interface for documentation.
  215. */
  216. public InstructionHandle[] getInstructions(){
  217. InstructionHandle[] ret = new InstructionHandle[instructions.size()];
  218. return (InstructionHandle[]) instructions.toArray(ret);
  219. }
  220. /*
  221. * Adds an instruction to this subroutine.
  222. * All instructions must have been added before invoking setLeavingRET().
  223. * @see #setLeavingRET
  224. */
  225. void addInstruction(InstructionHandle ih){
  226. if (theRET != null){
  227. throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET().");
  228. }
  229. instructions.add(ih);
  230. }
  231. /* Satisfies Subroutine.getRecursivelyAccessedLocalsIndices(). */
  232. public int[] getRecursivelyAccessedLocalsIndices(){
  233. HashSet s = new HashSet();
  234. int[] lvs = getAccessedLocalsIndices();
  235. for (int j=0; j<lvs.length; j++){
  236. s.add(new Integer(lvs[j]));
  237. }
  238. _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs());
  239. int[] ret = new int[s.size()];
  240. Iterator i = s.iterator();
  241. int j=-1;
  242. while (i.hasNext()){
  243. j++;
  244. ret[j] = ((Integer) i.next()).intValue();
  245. }
  246. return ret;
  247. }
  248. /**
  249. * A recursive helper method for getRecursivelyAccessedLocalsIndices().
  250. * @see #getRecursivelyAccessedLocalsIndices()
  251. */
  252. private void _getRecursivelyAccessedLocalsIndicesHelper(HashSet s, Subroutine[] subs){
  253. for (int i=0; i<subs.length; i++){
  254. int[] lvs = subs[i].getAccessedLocalsIndices();
  255. for (int j=0; j<lvs.length; j++){
  256. s.add(new Integer(lvs[j]));
  257. }
  258. if(subs[i].subSubs().length != 0){
  259. _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs());
  260. }
  261. }
  262. }
  263. /*
  264. * Satisfies Subroutine.getAccessedLocalIndices().
  265. */
  266. public int[] getAccessedLocalsIndices(){
  267. //TODO: Implement caching.
  268. HashSet acc = new HashSet();
  269. if (theRET == null && this != TOPLEVEL){
  270. throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals.");
  271. }
  272. Iterator i = instructions.iterator();
  273. while (i.hasNext()){
  274. InstructionHandle ih = (InstructionHandle) i.next();
  275. // RET is not a LocalVariableInstruction in the current version of BCEL.
  276. if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){
  277. int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
  278. acc.add(new Integer(idx));
  279. // LONG? DOUBLE?.
  280. try{
  281. // LocalVariableInstruction instances are typed without the need to look into
  282. // the constant pool.
  283. if (ih.getInstruction() instanceof LocalVariableInstruction){
  284. int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
  285. if (s==2) acc.add(new Integer(idx+1));
  286. }
  287. }
  288. catch(RuntimeException re){
  289. throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object.");
  290. }
  291. }
  292. }
  293. int[] ret = new int[acc.size()];
  294. i = acc.iterator();
  295. int j=-1;
  296. while (i.hasNext()){
  297. j++;
  298. ret[j] = ((Integer) i.next()).intValue();
  299. }
  300. return ret;
  301. }
  302. /*
  303. * Satisfies Subroutine.subSubs().
  304. */
  305. public Subroutine[] subSubs(){
  306. HashSet h = new HashSet();
  307. Iterator i = instructions.iterator();
  308. while (i.hasNext()){
  309. Instruction inst = ((InstructionHandle) i.next()).getInstruction();
  310. if (inst instanceof JsrInstruction){
  311. InstructionHandle targ = ((JsrInstruction) inst).getTarget();
  312. h.add(getSubroutine(targ));
  313. }
  314. }
  315. Subroutine[] ret = new Subroutine[h.size()];
  316. return (Subroutine[]) h.toArray(ret);
  317. }
  318. /*
  319. * Sets the local variable slot the ASTORE that is targeted
  320. * by the JsrInstructions of this subroutine operates on.
  321. * This subroutine's RET operates on that same local variable
  322. * slot, of course.
  323. */
  324. void setLocalVariable(int i){
  325. if (localVariable != UNSET){
  326. throw new AssertionViolatedException("localVariable set twice.");
  327. }
  328. else{
  329. localVariable = i;
  330. }
  331. }
  332. /**
  333. * The default constructor.
  334. */
  335. public SubroutineImpl(){
  336. }
  337. }// end Inner Class SubrouteImpl
  338. /**
  339. * The Hashtable containing the subroutines found.
  340. * Key: InstructionHandle of the leader of the subroutine.
  341. * Elements: SubroutineImpl objects.
  342. */
  343. private Hashtable subroutines = new Hashtable();
  344. /**
  345. * This is referring to a special subroutine, namely the
  346. * top level. This is not really a subroutine but we use
  347. * it to distinguish between top level instructions and
  348. * unreachable instructions.
  349. */
  350. public final Subroutine TOPLEVEL;
  351. /**
  352. * Constructor.
  353. * @param il A MethodGen object representing method to
  354. * create the Subroutine objects of.
  355. */
  356. public Subroutines(MethodGen mg){
  357. InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
  358. CodeExceptionGen[] handlers = mg.getExceptionHandlers();
  359. // Define our "Toplevel" fake subroutine.
  360. TOPLEVEL = new SubroutineImpl();
  361. // Calculate "real" subroutines.
  362. HashSet sub_leaders = new HashSet(); // Elements: InstructionHandle
  363. InstructionHandle ih = all[0];
  364. for (int i=0; i<all.length; i++){
  365. Instruction inst = all[i].getInstruction();
  366. if (inst instanceof JsrInstruction){
  367. sub_leaders.add(((JsrInstruction) inst).getTarget());
  368. }
  369. }
  370. // Build up the database.
  371. Iterator iter = sub_leaders.iterator();
  372. while (iter.hasNext()){
  373. SubroutineImpl sr = new SubroutineImpl();
  374. InstructionHandle astore = (InstructionHandle) (iter.next());
  375. sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() );
  376. subroutines.put(astore, sr);
  377. }
  378. // Fake it a bit. We want a virtual "TopLevel" subroutine.
  379. subroutines.put(all[0], TOPLEVEL);
  380. sub_leaders.add(all[0]);
  381. // Tell the subroutines about their JsrInstructions.
  382. // Note that there cannot be a JSR targeting the top-level
  383. // since "Jsr 0" is disallowed in Pass 3a.
  384. // Instructions shared by a subroutine and the toplevel are
  385. // disallowed and checked below, after the BFS.
  386. for (int i=0; i<all.length; i++){
  387. Instruction inst = all[i].getInstruction();
  388. if (inst instanceof JsrInstruction){
  389. InstructionHandle leader = ((JsrInstruction) inst).getTarget();
  390. ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
  391. }
  392. }
  393. // Now do a BFS from every subroutine leader to find all the
  394. // instructions that belong to a subroutine.
  395. HashSet instructions_assigned = new HashSet(); // we don't want to assign an instruction to two or more Subroutine objects.
  396. Hashtable colors = new Hashtable(); //Graph colouring. Key: InstructionHandle, Value: java.awt.Color .
  397. iter = sub_leaders.iterator();
  398. while (iter.hasNext()){
  399. // Do some BFS with "actual" as the root of the graph.
  400. InstructionHandle actual = (InstructionHandle) (iter.next());
  401. // Init colors
  402. for (int i=0; i<all.length; i++){
  403. colors.put(all[i], Color.white);
  404. }
  405. colors.put(actual, Color.gray);
  406. // Init Queue
  407. ArrayList Q = new ArrayList();
  408. Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.
  409. /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
  410. if (actual == all[0]){
  411. for (int j=0; j<handlers.length; j++){
  412. colors.put(handlers[j].getHandlerPC(), Color.gray);
  413. Q.add(handlers[j].getHandlerPC());
  414. }
  415. }
  416. /* CONTINUE NORMAL BFS ALGORITHM */
  417. // Loop until Queue is empty
  418. while (Q.size() != 0){
  419. InstructionHandle u = (InstructionHandle) Q.remove(0);
  420. InstructionHandle[] successors = getSuccessors(u);
  421. for (int i=0; i<successors.length; i++){
  422. if (((Color) colors.get(successors[i])) == Color.white){
  423. colors.put(successors[i], Color.gray);
  424. Q.add(successors[i]);
  425. }
  426. }
  427. colors.put(u, Color.black);
  428. }
  429. // BFS ended above.
  430. for (int i=0; i<all.length; i++){
  431. if (colors.get(all[i]) == Color.black){
  432. ((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(all[i]);
  433. if (instructions_assigned.contains(all[i])){
  434. throw new StructuralCodeConstraintException("Instruction '"+all[i]+"' is part of more than one subroutine (or of the top level and a subroutine).");
  435. }
  436. else{
  437. instructions_assigned.add(all[i]);
  438. }
  439. }
  440. }
  441. if (actual != all[0]){// If we don't deal with the top-level 'subroutine'
  442. ((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
  443. }
  444. }
  445. // Now make sure no instruction of a Subroutine is protected by exception handling code
  446. // as is mandated by JustIces notion of subroutines.
  447. for (int i=0; i<handlers.length; i++){
  448. InstructionHandle _protected = handlers[i].getStartPC();
  449. while (_protected != handlers[i].getEndPC().getNext()){// Note the inclusive/inclusive notation of "generic API" exception handlers!
  450. Enumeration subs = subroutines.elements();
  451. while (subs.hasMoreElements()){
  452. Subroutine sub = (Subroutine) subs.nextElement();
  453. if (sub != subroutines.get(all[0])){ // We don't want to forbid top-level exception handlers.
  454. if (sub.contains(_protected)){
  455. throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+"' is protected by an exception handler, '"+handlers[i]+"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
  456. }
  457. }
  458. }
  459. _protected = _protected.getNext();
  460. }
  461. }
  462. // Now make sure no subroutine is calling a subroutine
  463. // that uses the same local variable for the RET as themselves
  464. // (recursively).
  465. // This includes that subroutines may not call themselves
  466. // recursively, even not through intermediate calls to other
  467. // subroutines.
  468. noRecursiveCalls(getTopLevel(), new HashSet());
  469. }
  470. /**
  471. * This (recursive) utility method makes sure that
  472. * no subroutine is calling a subroutine
  473. * that uses the same local variable for the RET as themselves
  474. * (recursively).
  475. * This includes that subroutines may not call themselves
  476. * recursively, even not through intermediate calls to other
  477. * subroutines.
  478. *
  479. * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
  480. */
  481. private void noRecursiveCalls(Subroutine sub, HashSet set){
  482. Subroutine[] subs = sub.subSubs();
  483. for (int i=0; i<subs.length; i++){
  484. int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex();
  485. if (!set.add(new Integer(index))){
  486. // Don't use toString() here because of possibly infinite recursive subSubs() calls then.
  487. SubroutineImpl si = (SubroutineImpl) subs[i];
  488. throw new StructuralCodeConstraintException("Subroutine with local variable '"+si.localVariable+"', JSRs '"+si.theJSRs+"', RET '"+si.theRET+"' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both.");
  489. }
  490. noRecursiveCalls(subs[i], set);
  491. set.remove(new Integer(index));
  492. }
  493. }
  494. /**
  495. * Returns the Subroutine object associated with the given
  496. * leader (that is, the first instruction of the subroutine).
  497. * You must not use this to get the top-level instructions
  498. * modeled as a Subroutine object.
  499. *
  500. * @see #getTopLevel()
  501. */
  502. public Subroutine getSubroutine(InstructionHandle leader){
  503. Subroutine ret = (Subroutine) subroutines.get(leader);
  504. if (ret == null){
  505. throw new AssertionViolatedException("Subroutine requested for an InstructionHandle that is not a leader of a subroutine.");
  506. }
  507. if (ret == TOPLEVEL){
  508. throw new AssertionViolatedException("TOPLEVEL special subroutine requested; use getTopLevel().");
  509. }
  510. return ret;
  511. }
  512. /**
  513. * Returns the subroutine object associated with the
  514. * given instruction. This is a costly operation, you
  515. * should consider using getSubroutine(InstructionHandle).
  516. * Returns 'null' if the given InstructionHandle lies
  517. * in so-called 'dead code', i.e. code that can never
  518. * be executed.
  519. *
  520. * @see #getSubroutine(InstructionHandle)
  521. * @see #getTopLevel()
  522. */
  523. public Subroutine subroutineOf(InstructionHandle any){
  524. Iterator i = subroutines.values().iterator();
  525. while (i.hasNext()){
  526. Subroutine s = (Subroutine) i.next();
  527. if (s.contains(any)) return s;
  528. }
  529. System.err.println("DEBUG: Please verify '"+any+"' lies in dead code.");
  530. return null;
  531. //throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD CODE?).");
  532. }
  533. /**
  534. * For easy handling, the piece of code that is <B>not</B> a
  535. * subroutine, the top-level, is also modeled as a Subroutine
  536. * object.
  537. * It is a special Subroutine object where <B>you must not invoke
  538. * getEnteringJsrInstructions() or getLeavingRET()</B>.
  539. *
  540. * @see Subroutine#getEnteringJsrInstructions()
  541. * @see Subroutine#getLeavingRET()
  542. */
  543. public Subroutine getTopLevel(){
  544. return TOPLEVEL;
  545. }
  546. /**
  547. * A utility method that calculates the successors of a given InstructionHandle
  548. * <B>in the same subroutine</B>. That means, a RET does not have any successors
  549. * as defined here. A JsrInstruction has its physical successor as its successor
  550. * (opposed to its target) as defined here.
  551. */
  552. private static InstructionHandle[] getSuccessors(InstructionHandle instruction){
  553. final InstructionHandle[] empty = new InstructionHandle[0];
  554. final InstructionHandle[] single = new InstructionHandle[1];
  555. final InstructionHandle[] pair = new InstructionHandle[2];
  556. Instruction inst = instruction.getInstruction();
  557. if (inst instanceof RET){
  558. return empty;
  559. }
  560. // Terminates method normally.
  561. if (inst instanceof ReturnInstruction){
  562. return empty;
  563. }
  564. // Terminates method abnormally, because JustIce mandates
  565. // subroutines not to be protected by exception handlers.
  566. if (inst instanceof ATHROW){
  567. return empty;
  568. }
  569. // See method comment.
  570. if (inst instanceof JsrInstruction){
  571. single[0] = instruction.getNext();
  572. return single;
  573. }
  574. if (inst instanceof GotoInstruction){
  575. single[0] = ((GotoInstruction) inst).getTarget();
  576. return single;
  577. }
  578. if (inst instanceof BranchInstruction){
  579. if (inst instanceof Select){
  580. // BCEL's getTargets() returns only the non-default targets,
  581. // thanks to Eli Tilevich for reporting.
  582. InstructionHandle[] matchTargets = ((Select) inst).getTargets();
  583. InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
  584. ret[0] = ((Select) inst).getTarget();
  585. System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
  586. return ret;
  587. }
  588. else{
  589. pair[0] = instruction.getNext();
  590. pair[1] = ((BranchInstruction) inst).getTarget();
  591. return pair;
  592. }
  593. }
  594. // default case: Fall through.
  595. single[0] = instruction.getNext();
  596. return single;
  597. }
  598. /**
  599. * Returns a String representation of this object; merely for debugging puposes.
  600. */
  601. public String toString(){
  602. return "---\n"+subroutines.toString()+"\n---\n";
  603. }
  604. }