1 /*
   2  * Copyright (c) 2001, 2015, 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  * @author Robert Field
  30  *
  31  * @run build TestScaffold VMConnection TargetListener TargetAdapter
  32  * @run compile -g PopAsynchronousTest.java
  33  * @run driver PopAsynchronousTest
  34  */
  35 import com.sun.jdi.*;
  36 import com.sun.jdi.event.*;
  37 import com.sun.jdi.request.*;
  38 
  39 import java.util.*;
  40 
  41     /********** target program **********/
  42 
  43 class PopAsynchronousTarg {
  44     static final int N = 30;
  45     int fibonacci(int n) {
  46         if (n <= 2) {
  47             return 1;
  48         } else {
  49             return fibonacci(n-1) + fibonacci(n-2);
  50         }
  51     }
  52     void report(int n, int result) {
  53         System.out.println("fibonacci(" + n + ") = " + result);
  54     }
  55     public static void main(String[] args){
  56         int n = N;
  57         System.out.println("Howdy!");
  58         PopAsynchronousTarg pat = new PopAsynchronousTarg();
  59         pat.report(n, pat.fibonacci(n));
  60         System.out.println("Goodbye from PopAsynchronousTarg!");
  61     }
  62 }
  63 
  64     /********** test program **********/
  65 
  66 public class PopAsynchronousTest extends TestScaffold {
  67     ReferenceType targetClass;
  68     ThreadReference mainThread;
  69     int result = -1;
  70     boolean harassTarget = true;
  71     Object harassLock = new Object();
  72 
  73     PopAsynchronousTest (String args[]) {
  74         super(args);
  75     }
  76 
  77     public static void main(String[] args)      throws Exception {
  78         new PopAsynchronousTest(args).startTests();
  79     }
  80 
  81 
  82 
  83     /********** event handlers **********/
  84 
  85 
  86     public void breakpointReached(BreakpointEvent event) {
  87         harassTarget = false;
  88         synchronized(harassLock) {
  89             try {
  90                 StackFrame frame = event.thread().frame(0);
  91                 LocalVariable lv = frame.visibleVariableByName("result");
  92                 IntegerValue resultV = (IntegerValue)frame.getValue(lv);
  93                 result = resultV.value();
  94             } catch (Exception exc) {
  95                 exc.printStackTrace(System.err);
  96                 failure("TEST FAILURE: exception " + exc);
  97             }
  98         }
  99     }
 100 
 101     /********** test assist **********/
 102 
 103 
 104     class HarassThread extends Thread {
 105         public void run() {
 106             int harassCount = 0;
 107             try {
 108                 int prev = 0;
 109                 int delayTime = 1;
 110 
 111                 synchronized(harassLock) {
 112                     while (harassTarget && (harassCount < 10)) {
 113                         boolean backoff = true;
 114                         mainThread.suspend();
 115                         StackFrame top = mainThread.frame(0);
 116                         Method meth = top.location().method();
 117                         String methName = meth.name();
 118                         if (methName.equals("fibonacci")) {
 119                             LocalVariable lv = top.visibleVariableByName("n");
 120                             IntegerValue nV = (IntegerValue)top.getValue(lv);
 121                             int n = nV.value();
 122                             if (n != prev) {
 123                                 backoff = false;
 124                                 StackFrame popThis = top;
 125                                 Iterator it = mainThread.frames().iterator();
 126 
 127                                 /* pop lowest fibonacci frame */
 128                                 while (it.hasNext()) {
 129                                     StackFrame frame = (StackFrame)it.next();
 130                                     if (!frame.location().method().name().equals("fibonacci")) {
 131                                         break;
 132                                     }
 133                                     popThis = frame;
 134                                 }
 135                                 println("popping fibonacci(" + n + ")");
 136                                 mainThread.popFrames(popThis);
 137                                 ++harassCount;
 138                                 prev = n;
 139                             } else {
 140                                 println("ignoring another fibonacci(" + n + ")");
 141                             }
 142                         } else {
 143                             println("ignoring " + methName);
 144                         }
 145                         if (backoff) {
 146                             delayTime *= 2;
 147                         } else {
 148                             delayTime /= 2;
 149                             if (delayTime < harassCount) {
 150                                 delayTime = harassCount;
 151                             }
 152                         }
 153                         mainThread.resume();
 154                         println("Delaying for " + delayTime + "ms");
 155                         Thread.sleep(delayTime);
 156                     }
 157                 }
 158             } catch (Exception exc) {
 159                 exc.printStackTrace(System.err);
 160                 failure("TEST FAILURE: exception " + exc);
 161             }
 162             println("Harassment complete, count = " + harassCount);
 163         }
 164     }
 165 
 166     /********** test core **********/
 167 
 168     protected void runTests() throws Exception {
 169         /*
 170          * Get to the top of main()
 171          * to determine targetClass and mainThread
 172          */
 173         BreakpointEvent bpe = startToMain("PopAsynchronousTarg");
 174         targetClass = bpe.location().declaringType();
 175         mainThread = bpe.thread();
 176         EventRequestManager erm = vm().eventRequestManager();
 177 
 178         /*
 179          * Set event requests
 180          */
 181         List meths = targetClass.methodsByName("report");
 182         Location loc = ((Method)(meths.get(0))).location();
 183         BreakpointRequest request = erm.createBreakpointRequest(loc);
 184         request.enable();
 185 
 186         /*
 187          * start popping wildly away
 188          */
 189         (new HarassThread()).start();
 190 
 191         /*
 192          * resume the target listening for events
 193          */
 194         listenUntilVMDisconnect();
 195 
 196         /*
 197          * check result
 198          */
 199         int correct = (new PopAsynchronousTarg()).
 200             fibonacci(PopAsynchronousTarg.N);
 201         if (result == correct) {
 202             println("Got expected result: " + result);
 203         } else {
 204             failure("FAIL: expected result: " + correct +
 205                     ", got: " + result);
 206         }
 207 
 208         /*
 209          * deal with results of test
 210          * if anything has called failure("foo") testFailed will be true
 211          */
 212         if (!testFailed) {
 213             println("PopAsynchronousTest: passed");
 214         } else {
 215             throw new Exception("PopAsynchronousTest: failed");
 216         }
 217     }
 218 }