agent/test/jdi/TestScaffold.java

Mon, 28 Jul 2014 15:06:38 -0700

author
fzhinkin
date
Mon, 28 Jul 2014 15:06:38 -0700
changeset 6997
dbb05f6d93c4
parent 1907
c18cbe5936b8
child 6876
710a3c8b516e
permissions
-rw-r--r--

8051344: JVM crashed in Compile::start() during method parsing w/ UseRTMDeopt turned on
Summary: call rtm_deopt() only if there were no compilation bailouts before.
Reviewed-by: kvn

     1 /*
     2  * Copyright (c) 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  */
    25 import com.sun.jdi.*;
    26 import com.sun.jdi.request.*;
    27 import com.sun.jdi.event.*;
    28 import java.util.*;
    29 import java.io.*;
    31 /**
    32  * Framework used by all JDI regression tests
    33  */
    34 abstract public class TestScaffold extends TargetAdapter {
    35     private boolean shouldTrace = false;
    36     private VMConnection connection;
    37     private VirtualMachine vm;
    38     private EventRequestManager requestManager;
    39     private List listeners = Collections.synchronizedList(new LinkedList());
    41     /**
    42      * We create a VMDeathRequest, SUSPEND_ALL, to sync the BE and FE.
    43      */
    44     //private VMDeathRequest ourVMDeathRequest = null;
    45     Object ourVMDeathRequest = null;
    47     /**
    48      * We create an ExceptionRequest, SUSPEND_NONE so that we can
    49      * catch it and output a msg if an exception occurs in the
    50      * debuggee.
    51      */
    52     private ExceptionRequest ourExceptionRequest = null;
    54     /**
    55      * If we do catch an uncaught exception, we set this true
    56      * so the testcase can find out if it wants to.
    57      */
    58     private boolean exceptionCaught = false;
    59     ThreadReference vmStartThread = null;
    60     boolean vmDied = false;
    61     boolean vmDisconnected = false;
    62     final String[] args;
    63     protected boolean testFailed = false;
    65     static private class ArgInfo {
    66         String targetVMArgs = "";
    67         String targetAppCommandLine = "";
    68         String connectorSpec = "com.sun.jdi.CommandLineLaunch:";
    69         int traceFlags = 0;
    70     }
    72     /**
    73      * An easy way to sleep for awhile
    74      */
    75     public void mySleep(int millis) {
    76         try {
    77             Thread.sleep(millis);
    78         } catch (InterruptedException ee) {
    79         }
    80     }
    82     boolean getExceptionCaught() {
    83         return exceptionCaught;
    84     }
    86     void setExceptionCaught(boolean value) {
    87         exceptionCaught = value;
    88     }
    90     /**
    91      * Return true if eventSet contains the VMDeathEvent for the request in
    92      * the ourVMDeathRequest ivar.
    93      */
    94     private boolean containsOurVMDeathRequest(EventSet eventSet) {
    95         if (ourVMDeathRequest != null) {
    96             Iterator myIter = eventSet.iterator();
    97             while (myIter.hasNext()) {
    98                 Event myEvent = (Event)myIter.next();
    99                 if (!(myEvent instanceof VMDeathEvent)) {
   100                     // We assume that an EventSet contains only VMDeathEvents
   101                     // or no VMDeathEvents.
   102                     break;
   103                 }
   104                 if (ourVMDeathRequest.equals(myEvent.request())) {
   105                     return true;
   106                 }
   107             }
   108         }
   109         return false;
   110     }
   112     /************************************************************************
   113      * The following methods override those in our base class, TargetAdapter.
   114      *************************************************************************/
   116     /**
   117      * Events handled directly by scaffold always resume (well, almost always)
   118      */
   119     public void eventSetComplete(EventSet set) {
   120         // The listener in connect(..) resumes after receiving our
   121         // special VMDeathEvent.  We can't also do the resume
   122         // here or we will probably get a VMDisconnectedException
   123         if (!containsOurVMDeathRequest(set)) {
   124             traceln("TS: set.resume() called");
   125             set.resume();
   126         }
   127     }
   129     /**
   130      * This method sets up default requests.
   131      * Testcases can override this to change default behavior.
   132      */
   133     protected void createDefaultEventRequests() {
   134         createDefaultVMDeathRequest();
   135         createDefaultExceptionRequest();
   136     }
   138     /**
   139      * We want the BE to stop when it issues a VMDeathEvent in order to
   140      * give the FE time to complete handling events that occured before
   141      * the VMDeath.  When we get the VMDeathEvent for this request in
   142      * the listener in connect(), we will do a resume.
   143      * If a testcase wants to do something special with VMDeathEvent's,
   144      * then it should override this method with an empty method or
   145      * whatever in order to suppress the automatic resume.  The testcase
   146      * will then be responsible for the handling of VMDeathEvents.  It
   147      * has to be sure that it does a resume if it gets a VMDeathEvent
   148      * with SUSPEND_ALL, and it has to be sure that it doesn't do a
   149      * resume after getting a VMDeath with SUSPEND_NONE (the automatically
   150      * generated VMDeathEvent.)
   151      */
   152     protected void createDefaultVMDeathRequest() {
   153 //         ourVMDeathRequest = requestManager.createVMDeathRequest();
   154 //         ourVMDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
   155 //         ourVMDeathRequest.enable();
   156     }
   158     /**
   159      * This will allow us to print a warning if a debuggee gets an
   160      * unexpected exception.  The unexpected exception will be handled in
   161      * the exceptionThrown method in the listener created in the connect()
   162      * method.
   163      * If a testcase does not want an uncaught exception to cause a
   164      * msg, it must override this method.
   165      */
   166     protected void createDefaultExceptionRequest() {
   167         ourExceptionRequest = requestManager.createExceptionRequest(null,
   168                                                                 false, true);
   170         // We can't afford to make this be other than SUSPEND_NONE.  Otherwise,
   171         // it would have to be resumed.  If our connect() listener resumes it,
   172         // what about the case where the EventSet contains other events with
   173         // SUSPEND_ALL and there are other listeners who expect the BE to still
   174         // be suspended when their handlers get called?
   175         ourExceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
   176         ourExceptionRequest.enable();
   177     }
   179     private class EventHandler implements Runnable {
   180         EventHandler() {
   181             Thread thread = new Thread(this);
   182             thread.setDaemon(true);
   183             thread.start();
   184         }
   186         private void notifyEvent(TargetListener listener, Event event) {
   187             if (event instanceof BreakpointEvent) {
   188                 listener.breakpointReached((BreakpointEvent)event);
   189             } else if (event instanceof ExceptionEvent) {
   190                 listener.exceptionThrown((ExceptionEvent)event);
   191             } else if (event instanceof StepEvent) {
   192                 listener.stepCompleted((StepEvent)event);
   193             } else if (event instanceof ClassPrepareEvent) {
   194                 listener.classPrepared((ClassPrepareEvent)event);
   195             } else if (event instanceof ClassUnloadEvent) {
   196                 listener.classUnloaded((ClassUnloadEvent)event);
   197             } else if (event instanceof MethodEntryEvent) {
   198                 listener.methodEntered((MethodEntryEvent)event);
   199             } else if (event instanceof MethodExitEvent) {
   200                 listener.methodExited((MethodExitEvent)event);
   201             } else if (event instanceof AccessWatchpointEvent) {
   202                 listener.fieldAccessed((AccessWatchpointEvent)event);
   203             } else if (event instanceof ModificationWatchpointEvent) {
   204                 listener.fieldModified((ModificationWatchpointEvent)event);
   205             } else if (event instanceof ThreadStartEvent) {
   206                 listener.threadStarted((ThreadStartEvent)event);
   207             } else if (event instanceof ThreadDeathEvent) {
   208                 listener.threadDied((ThreadDeathEvent)event);
   209             } else if (event instanceof VMStartEvent) {
   210                 listener.vmStarted((VMStartEvent)event);
   211             } else if (event instanceof VMDeathEvent) {
   212                 listener.vmDied((VMDeathEvent)event);
   213             } else if (event instanceof VMDisconnectEvent) {
   214                 listener.vmDisconnected((VMDisconnectEvent)event);
   215             } else {
   216                 throw new InternalError("Unknown event type: " + event.getClass());
   217             }
   218         }
   220         private void traceSuspendPolicy(int policy) {
   221             if (shouldTrace) {
   222                 switch (policy) {
   223                 case EventRequest.SUSPEND_NONE:
   224                     traceln("TS: eventHandler: suspend = SUSPEND_NONE");
   225                     break;
   226                 case EventRequest.SUSPEND_ALL:
   227                     traceln("TS: eventHandler: suspend = SUSPEND_ALL");
   228                     break;
   229                 case EventRequest.SUSPEND_EVENT_THREAD:
   230                     traceln("TS: eventHandler: suspend = SUSPEND_EVENT_THREAD");
   231                     break;
   232                 }
   233             }
   234         }
   236         public void run() {
   237             boolean connected = true;
   238             do {
   239                 try {
   240                     EventSet set = vm.eventQueue().remove();
   241                     traceSuspendPolicy(set.suspendPolicy());
   242                     synchronized (listeners) {
   243                         ListIterator iter = listeners.listIterator();
   244                         while (iter.hasNext()) {
   245                             TargetListener listener = (TargetListener)iter.next();
   246                             traceln("TS: eventHandler: listener = " + listener);
   247                             listener.eventSetReceived(set);
   248                             if (listener.shouldRemoveListener()) {
   249                                 iter.remove();
   250                             } else {
   251                                 Iterator jter = set.iterator();
   252                                 while (jter.hasNext()) {
   253                                     Event event = (Event)jter.next();
   254                                     traceln("TS: eventHandler:    event = " + event.getClass());
   256                                     if (event instanceof VMDisconnectEvent) {
   257                                         connected = false;
   258                                     }
   259                                     listener.eventReceived(event);
   260                                     if (listener.shouldRemoveListener()) {
   261                                         iter.remove();
   262                                         break;
   263                                     }
   264                                     notifyEvent(listener, event);
   265                                     if (listener.shouldRemoveListener()) {
   266                                         iter.remove();
   267                                         break;
   268                                     }
   269                                 }
   270                                 traceln("TS: eventHandler:   end of events loop");
   271                                 if (!listener.shouldRemoveListener()) {
   272                                     traceln("TS: eventHandler:   calling ESC");
   273                                     listener.eventSetComplete(set);
   274                                     if (listener.shouldRemoveListener()) {
   275                                         iter.remove();
   276                                     }
   277                                 }
   278                             }
   279                             traceln("TS: eventHandler: end of listeners loop");
   280                         }
   281                     }
   282                 } catch (InterruptedException e) {
   283                     traceln("TS: eventHandler: InterruptedException");
   284                 } catch (Exception e) {
   285                     failure("FAILED: Exception occured in eventHandler: " + e);
   286                     e.printStackTrace();
   287                     connected = false;
   288                     synchronized(TestScaffold.this) {
   289                         // This will make the waiters such as waitForVMDisconnect
   290                         // exit their wait loops.
   291                         vmDisconnected = true;
   292                         TestScaffold.this.notifyAll();
   293                     }
   294                 }
   295                 traceln("TS: eventHandler: End of outerloop");
   296             } while (connected);
   297             traceln("TS: eventHandler: finished");
   298         }
   299     }
   301     /**
   302      * Constructor
   303      */
   304     public TestScaffold(String[] args) {
   305         this.args = args;
   306     }
   308     public void enableScaffoldTrace() {
   309         this.shouldTrace = true;
   310     }
   312     public void disableScaffoldTrace() {
   313         this.shouldTrace = false;
   314     }
   317     protected void startUp(String targetName) {
   318         List argList = new ArrayList(Arrays.asList(args));
   319         argList.add(targetName);
   320         println("run args: " + argList);
   321         connect((String[]) argList.toArray(args));
   322         waitForVMStart();
   323     }
   325     protected BreakpointEvent startToMain(String targetName) {
   326         startUp(targetName);
   327         traceln("TS: back from startUp");
   328         BreakpointEvent bpr = resumeTo(targetName, "main", "([Ljava/lang/String;)V");
   329         waitForInput();
   330         return bpr;
   331     }
   333     protected void waitForInput() {
   334         if (System.getProperty("jpda.wait") != null) {
   335             try {
   336                 System.err.println("Press <enter> to continue");
   337                 System.in.read();
   338                 System.err.println("running...");
   340             } catch(Exception e) {
   341             }
   342         }
   343     }
   345     /*
   346      * Test cases should implement tests in runTests and should
   347      * initiate testing by calling run().
   348      */
   349     abstract protected void runTests() throws Exception;
   351     final public void startTests() throws Exception {
   352         try {
   353             runTests();
   354         } finally {
   355             shutdown();
   356         }
   357     }
   359     protected void println(String str) {
   360         System.err.println(str);
   361     }
   363     protected void print(String str) {
   364         System.err.print(str);
   365     }
   367     protected void traceln(String str) {
   368         if (shouldTrace) {
   369             println(str);
   370         }
   371     }
   373     protected void failure(String str) {
   374         println(str);
   375         testFailed = true;
   376     }
   378     private ArgInfo parseArgs(String args[]) {
   379         ArgInfo argInfo = new ArgInfo();
   380         for (int i = 0; i < args.length; i++) {
   381             if (args[i].equals("-connect")) {
   382                 i++;
   383                 argInfo.connectorSpec = args[i];
   384             } else if (args[i].equals("-trace")) {
   385                 i++;
   386                 argInfo.traceFlags = Integer.decode(args[i]).intValue();
   387             } else if (args[i].startsWith("-J")) {
   388                 argInfo.targetVMArgs += (args[i].substring(2) + ' ');
   390                 /*
   391                  * classpath can span two arguments so we need to handle
   392                  * it specially.
   393                  */
   394                 if (args[i].equals("-J-classpath")) {
   395                     i++;
   396                     argInfo.targetVMArgs += (args[i] + ' ');
   397                 }
   398             } else {
   399                 argInfo.targetAppCommandLine += (args[i] + ' ');
   400             }
   401         }
   402         return argInfo;
   403     }
   405     /**
   406      * This is called to connect to a debuggee VM.  It starts the VM and
   407      * installs a listener to catch VMStartEvent, our default events, and
   408      * VMDisconnectedEvent.  When these events appear, that is remembered
   409      * and waiters are notified.
   410      * This is normally called in the main thread of the test case.
   411      * It starts up an EventHandler thread that gets events coming in
   412      * from the debuggee and distributes them to listeners.  That thread
   413      * keeps running until a VMDisconnectedEvent occurs or some exception
   414      * occurs during its processing.
   415      *
   416      * The 'listenUntilVMDisconnect' method adds 'this' as a listener.
   417      * This means that 'this's vmDied method will get called.  This has a
   418      * default impl in TargetAdapter.java which can be overridden in the
   419      * testcase.
   420      *
   421      * waitForRequestedEvent also adds an adaptor listener that listens
   422      * for the particular event it is supposed to wait for (and it also
   423      * catches VMDisconnectEvents.)  This listener is removed once
   424      * its eventReceived method is called.
   425      * waitForRequestedEvent is called by most of the methods to do bkpts,
   426      * etc.
   427      */
   428     public void connect(String args[]) {
   429         ArgInfo argInfo = parseArgs(args);
   431         argInfo.targetVMArgs += VMConnection.getDebuggeeVMOptions();
   432         connection = new VMConnection(argInfo.connectorSpec,
   433                                       argInfo.traceFlags);
   435         addListener(new TargetAdapter() {
   436                 public void eventSetComplete(EventSet set) {
   437                     if (TestScaffold.this.containsOurVMDeathRequest(set)) {
   438                         traceln("TS: connect: set.resume() called");
   439                         set.resume();
   441                         // Note that we want to do the above resume before
   442                         // waking up any sleepers.
   443                         synchronized(TestScaffold.this) {
   444                             TestScaffold.this.notifyAll();
   445                         }
   446                     }
   447                 }
   449                 public void vmStarted(VMStartEvent event) {
   450                     synchronized(TestScaffold.this) {
   451                         vmStartThread = event.thread();
   452                         TestScaffold.this.notifyAll();
   453                     }
   454                 }
   455                 /**
   456                  * By default, we catch uncaught exceptions and print a msg.
   457                  * The testcase must override the createDefaultExceptionRequest
   458                  * method if it doesn't want this behavior.
   459                  */
   460                 public void exceptionThrown(ExceptionEvent event) {
   461                     if (TestScaffold.this.ourExceptionRequest != null &&
   462                         TestScaffold.this.ourExceptionRequest.equals(
   463                                                         event.request())) {
   464                         println("Note: Unexpected Debuggee Exception: " +
   465                                 event.exception().referenceType().name() +
   466                                 " at line " + event.location().lineNumber());
   467                         TestScaffold.this.exceptionCaught = true;
   468                     }
   469                 }
   471                 public void vmDied(VMDeathEvent event) {
   472                     vmDied = true;
   473                     traceln("TS: vmDied called");
   474                 }
   476                 public void vmDisconnected(VMDisconnectEvent event) {
   477                     synchronized(TestScaffold.this) {
   478                         vmDisconnected = true;
   479                         TestScaffold.this.notifyAll();
   480                     }
   481                 }
   482             });
   483         if (connection.connector().name().equals("com.sun.jdi.CommandLineLaunch")) {
   484             if (argInfo.targetVMArgs.length() > 0) {
   485                 if (connection.connectorArg("options").length() > 0) {
   486                     throw new IllegalArgumentException("VM options in two places");
   487                 }
   488                 connection.setConnectorArg("options", argInfo.targetVMArgs);
   489             }
   490             if (argInfo.targetAppCommandLine.length() > 0) {
   491                 if (connection.connectorArg("main").length() > 0) {
   492                     throw new IllegalArgumentException("Command line in two places");
   493                 }
   494                 connection.setConnectorArg("main", argInfo.targetAppCommandLine);
   495             }
   496         }
   498         vm = connection.open();
   499         requestManager = vm.eventRequestManager();
   500         createDefaultEventRequests();
   501         new EventHandler();
   502     }
   505     public VirtualMachine vm() {
   506         return vm;
   507     }
   509     public EventRequestManager eventRequestManager() {
   510         return requestManager;
   511     }
   513     public void addListener(TargetListener listener) {
   514         traceln("TS: Adding listener " + listener);
   515         listeners.add(listener);
   516     }
   518     public void removeListener(TargetListener listener) {
   519         traceln("TS: Removing listener " + listener);
   520         listeners.remove(listener);
   521     }
   524     protected void listenUntilVMDisconnect() {
   525         try {
   526             addListener (this);
   527         } catch (Exception ex){
   528             ex.printStackTrace();
   529             testFailed = true;
   530         } finally {
   531             // Allow application to complete and shut down
   532             resumeToVMDisconnect();
   533         }
   534     }
   536     public synchronized ThreadReference waitForVMStart() {
   537         while ((vmStartThread == null) && !vmDisconnected) {
   538             try {
   539                 wait();
   540             } catch (InterruptedException e) {
   541             }
   542         }
   544         if (vmStartThread == null) {
   545             throw new VMDisconnectedException();
   546         }
   548         return vmStartThread;
   549     }
   551     public synchronized void waitForVMDisconnect() {
   552         traceln("TS: waitForVMDisconnect");
   553         while (!vmDisconnected) {
   554             try {
   555                 wait();
   556             } catch (InterruptedException e) {
   557             }
   558         }
   559         traceln("TS: waitForVMDisconnect: done");
   560     }
   562     public Event waitForRequestedEvent(final EventRequest request) {
   563         class EventNotification {
   564             Event event;
   565             boolean disconnected = false;
   566         }
   567         final EventNotification en = new EventNotification();
   569         TargetAdapter adapter = new TargetAdapter() {
   570             public void eventReceived(Event event) {
   571                 if (request.equals(event.request())) {
   572                     traceln("TS:Listener2: got requested event");
   573                     synchronized (en) {
   574                         en.event = event;
   575                         en.notifyAll();
   576                     }
   577                     removeThisListener();
   578                 } else if (event instanceof VMDisconnectEvent) {
   579                     traceln("TS:Listener2: got VMDisconnectEvent");
   580                     synchronized (en) {
   581                         en.disconnected = true;
   582                         en.notifyAll();
   583                     }
   584                     removeThisListener();
   585                 }
   586             }
   587         };
   589         addListener(adapter);
   591         try {
   592             synchronized (en) {
   593                 traceln("TS: waitForRequestedEvent: vm.resume called");
   594                 vm.resume();
   596                 while (!en.disconnected && (en.event == null)) {
   597                     en.wait();
   598                 }
   599             }
   600         } catch (InterruptedException e) {
   601             return null;
   602         }
   604         if (en.disconnected) {
   605             throw new RuntimeException("VM Disconnected before requested event occurred");
   606         }
   607         return en.event;
   608     }
   610     private StepEvent doStep(ThreadReference thread, int gran, int depth) {
   611         final StepRequest sr =
   612                   requestManager.createStepRequest(thread, gran, depth);
   614         sr.addClassExclusionFilter("java.*");
   615         sr.addClassExclusionFilter("sun.*");
   616         sr.addClassExclusionFilter("com.sun.*");
   617         sr.addCountFilter(1);
   618         sr.enable();
   619         StepEvent retEvent = (StepEvent)waitForRequestedEvent(sr);
   620         requestManager.deleteEventRequest(sr);
   621         return retEvent;
   622     }
   624     public StepEvent stepIntoInstruction(ThreadReference thread) {
   625         return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO);
   626     }
   628     public StepEvent stepIntoLine(ThreadReference thread) {
   629         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
   630     }
   632     public StepEvent stepOverInstruction(ThreadReference thread) {
   633         return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER);
   634     }
   636     public StepEvent stepOverLine(ThreadReference thread) {
   637         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER);
   638     }
   640     public StepEvent stepOut(ThreadReference thread) {
   641         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT);
   642     }
   644     public BreakpointEvent resumeTo(Location loc) {
   645         final BreakpointRequest request =
   646             requestManager.createBreakpointRequest(loc);
   647         request.addCountFilter(1);
   648         request.enable();
   649         return (BreakpointEvent)waitForRequestedEvent(request);
   650     }
   652     public ReferenceType findReferenceType(String name) {
   653         List rts = vm.classesByName(name);
   654         Iterator iter = rts.iterator();
   655         while (iter.hasNext()) {
   656             ReferenceType rt = (ReferenceType)iter.next();
   657             if (rt.name().equals(name)) {
   658                 return rt;
   659             }
   660         }
   661         return null;
   662     }
   664     public Method findMethod(ReferenceType rt, String name, String signature) {
   665         List methods = rt.methods();
   666         Iterator iter = methods.iterator();
   667         while (iter.hasNext()) {
   668             Method method = (Method)iter.next();
   669             if (method.name().equals(name) &&
   670                 method.signature().equals(signature)) {
   671                 return method;
   672             }
   673         }
   674         return null;
   675     }
   677     public Location findLocation(ReferenceType rt, int lineNumber)
   678                          throws AbsentInformationException {
   679         List locs = rt.locationsOfLine(lineNumber);
   680         if (locs.size() == 0) {
   681             throw new IllegalArgumentException("Bad line number");
   682         } else if (locs.size() > 1) {
   683             throw new IllegalArgumentException("Line number has multiple locations");
   684         }
   686         return (Location)locs.get(0);
   687     }
   689     public BreakpointEvent resumeTo(String clsName, String methodName,
   690                                          String methodSignature) {
   691         ReferenceType rt = findReferenceType(clsName);
   692         if (rt == null) {
   693             rt = resumeToPrepareOf(clsName).referenceType();
   694         }
   696         Method method = findMethod(rt, methodName, methodSignature);
   697         if (method == null) {
   698             throw new IllegalArgumentException("Bad method name/signature");
   699         }
   701         return resumeTo(method.location());
   702     }
   704     public BreakpointEvent resumeTo(String clsName, int lineNumber) throws AbsentInformationException {
   705         ReferenceType rt = findReferenceType(clsName);
   706         if (rt == null) {
   707             rt = resumeToPrepareOf(clsName).referenceType();
   708         }
   710         return resumeTo(findLocation(rt, lineNumber));
   711     }
   713     public ClassPrepareEvent resumeToPrepareOf(String className) {
   714         final ClassPrepareRequest request =
   715             requestManager.createClassPrepareRequest();
   716         request.addClassFilter(className);
   717         request.addCountFilter(1);
   718         request.enable();
   719         return (ClassPrepareEvent)waitForRequestedEvent(request);
   720     }
   722     public void resumeToVMDisconnect() {
   723         try {
   724             traceln("TS: resumeToVMDisconnect: vm.resume called");
   725             vm.resume();
   726         } catch (VMDisconnectedException e) {
   727             // clean up below
   728         }
   729         waitForVMDisconnect();
   730     }
   732     public void shutdown() {
   733         shutdown(null);
   734     }
   736     public void shutdown(String message) {
   737         traceln("TS: shutdown: vmDied= " + vmDied +
   738                  ", vmDisconnected= " + vmDisconnected +
   739                  ", connection = " + connection);
   741         if ((connection != null)) {
   742             try {
   743                 connection.disposeVM();
   744              } catch (VMDisconnectedException e) {
   745                 // Shutting down after the VM has gone away. This is
   746                 // not an error, and we just ignore it.
   747             }
   748         } else {
   749             traceln("TS: shutdown: disposeVM not called");
   750         }
   751         if (message != null) {
   752             println(message);
   753         }
   755         vmDied = true;
   756         vmDisconnected = true;
   757     }
   758 }

mercurial