1 /*
   2  * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  *  @test
  26  *  @bug 4467564
  27  *  @summary Test the popping of frames in an asynchronous context
  28  *           (that is, when suspended by the debugger at random points)
  29  *
  30  *  @author Robert Field
  31  *
  32  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  *  @run compile -g PopAsynchronousTest.java
  34  *  @run driver PopAsynchronousTest
  35  */
  36 import com.sun.jdi.*;
  37 import com.sun.jdi.event.*;
  38 import com.sun.jdi.request.*;
  39 
  40 import java.util.*;
  41 
  42     /********** target program **********/
  43 
  44 class PopAsynchronousTarg {
  45     static final int N = 30;
  46     int fibonacci(int n) {
  47         if (n <= 2) {
  48             return 1;
  49         } else {
  50             return fibonacci(n-1) + fibonacci(n-2);
  51         }
  52     }
  53     void report(int n, int result) {
  54         System.out.println("fibonacci(" + n + ") = " + result);
  55     }
  56     public static void main(String[] args){
  57         int n = N;
  58         System.out.println("Howdy!");
  59         PopAsynchronousTarg pat = new PopAsynchronousTarg();
  60         pat.report(n, pat.fibonacci(n));
  61         System.out.println("Goodbye from PopAsynchronousTarg!");
  62     }
  63 }
  64 
  65     /********** test program **********/
  66 
  67 public class PopAsynchronousTest extends TestScaffold {
  68     ReferenceType targetClass;
  69     ThreadReference mainThread;
  70     int result = -1;
  71     boolean harassTarget = true;
  72     Object harassLock = new Object();
  73 
  74     PopAsynchronousTest (String args[]) {
  75         super(args);
  76     }
  77 
  78     public static void main(String[] args)      throws Exception {
  79         new PopAsynchronousTest(args).startTests();
  80     }
  81 
  82 
  83 
  84     /********** event handlers **********/
  85 
  86 
  87     public void breakpointReached(BreakpointEvent event) {
  88         harassTarget = false;
  89         synchronized(harassLock) {
  90             try {
  91                 StackFrame frame = event.thread().frame(0);
  92                 LocalVariable lv = frame.visibleVariableByName("result");
  93                 IntegerValue resultV = (IntegerValue)frame.getValue(lv);
  94                 result = resultV.value();
  95             } catch (Exception exc) {
  96                 exc.printStackTrace(System.err);
  97                 failure("TEST FAILURE: exception " + exc);
  98             }
  99         }
 100     }
 101 
 102     /********** test assist **********/
 103 
 104 
 105     class HarassThread extends Thread {
 106         public void run() {
 107             int harassCount = 0;
 108             try {
 109                 int prev = 0;
 110                 int delayTime = 1;
 111 
 112                 synchronized(harassLock) {
 113                     while (harassTarget && (harassCount < 10)) {
 114                         boolean backoff = true;
 115                         mainThread.suspend();
 116                         StackFrame top = mainThread.frame(0);
 117                         Method meth = top.location().method();
 118                         String methName = meth.name();
 119                         if (methName.equals("fibonacci")) {
 120                             LocalVariable lv = top.visibleVariableByName("n");
 121                             IntegerValue nV = (IntegerValue)top.getValue(lv);
 122                             int n = nV.value();
 123                             if (n != prev) {
 124                                 backoff = false;
 125                                 StackFrame popThis = top;
 126                                 Iterator it = mainThread.frames().iterator();
 127 
 128                                 /* pop lowest fibonacci frame */
 129                                 while (it.hasNext()) {
 130                                     StackFrame frame = (StackFrame)it.next();
 131                                     if (!frame.location().method().name().equals("fibonacci")) {
 132                                         break;
 133                                     }
 134                                     popThis = frame;
 135                                 }
 136                                 println("popping fibonacci(" + n + ")");
 137                                 mainThread.popFrames(popThis);
 138                                 ++harassCount;
 139                                 prev = n;
 140                             } else {
 141                                 println("ignoring another fibonacci(" + n + ")");
 142                             }
 143                         } else {
 144                             println("ignoring " + methName);
 145                         }
 146                         if (backoff) {
 147                             delayTime *= 2;
 148                         } else {
 149                             delayTime /= 2;
 150                             if (delayTime < harassCount) {
 151                                 delayTime = harassCount;
 152                             }
 153                         }
 154                         mainThread.resume();
 155                         println("Delaying for " + delayTime + "ms");
 156                         Thread.sleep(delayTime);
 157                     }
 158                 }
 159             } catch (Exception exc) {
 160                 exc.printStackTrace(System.err);
 161                 failure("TEST FAILURE: exception " + exc);
 162             }
 163             println("Harassment complete, count = " + harassCount);
 164         }
 165     }
 166 
 167     /********** test core **********/
 168 
 169     protected void runTests() throws Exception {
 170         /*
 171          * Get to the top of main()
 172          * to determine targetClass and mainThread
 173          */
 174         BreakpointEvent bpe = startToMain("PopAsynchronousTarg");
 175         targetClass = bpe.location().declaringType();
 176         mainThread = bpe.thread();
 177         EventRequestManager erm = vm().eventRequestManager();
 178 
 179         /*
 180          * Set event requests
 181          */
 182         List meths = targetClass.methodsByName("report");
 183         Location loc = ((Method)(meths.get(0))).location();
 184         BreakpointRequest request = erm.createBreakpointRequest(loc);
 185         request.enable();
 186 
 187         /*
 188          * start popping wildly away
 189          */
 190         (new HarassThread()).start();
 191 
 192         /*
 193          * resume the target listening for events
 194          */
 195         listenUntilVMDisconnect();
 196 
 197         /*
 198          * check result
 199          */
 200         int correct = (new PopAsynchronousTarg()).
 201             fibonacci(PopAsynchronousTarg.N);
 202         if (result == correct) {
 203             println("Got expected result: " + result);
 204         } else {
 205             failure("FAIL: expected result: " + correct +
 206                     ", got: " + result);
 207         }
 208 
 209         /*
 210          * deal with results of test
 211          * if anything has called failure("foo") testFailed will be true
 212          */
 213         if (!testFailed) {
 214             println("PopAsynchronousTest: passed");
 215         } else {
 216             throw new Exception("PopAsynchronousTest: failed");
 217         }
 218     }
 219 }