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