test/jdk/com/sun/jdi/NashornPopFrameTest.java
changeset 48952 e999964446d7
equal deleted inserted replaced
48951:950c35ea6237 48952:e999964446d7
       
     1 /*
       
     2  * Copyright (c) 2001, 2018, 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 8187143
       
    27  * @summary JDI crash in ~BufferBlob::MethodHandles adapters
       
    28  *
       
    29  * @run build TestScaffold VMConnection TargetListener TargetAdapter
       
    30  * @run compile -g NashornPopFrameTest.java
       
    31  * @run driver NashornPopFrameTest
       
    32  */
       
    33 import com.sun.jdi.*;
       
    34 import com.sun.jdi.event.*;
       
    35 import com.sun.jdi.request.*;
       
    36 
       
    37 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
       
    38 import javax.script.*;
       
    39 
       
    40 import java.io.PrintStream;
       
    41 
       
    42 
       
    43 // The debuggee, creates and uses a Nashorn engine to evaluate a simple script.
       
    44 
       
    45 // The debugger  tries to set a breakpoint in Nashorn internal DEBUGGER method.
       
    46 // When the breakpoint is reached, it looks for stack frame whose method's
       
    47 // declaring type name starts with jdk.nashorn.internal.scripts.Script$.
       
    48 // (nashorn dynamically generated classes)
       
    49 // It then pops stack frames using the ThreadReference.popFrames() call, up to
       
    50 // and including the above stackframe.
       
    51 // The execution of the debuggee application is resumed after the needed
       
    52 // frames have been popped.
       
    53 
       
    54 class ScriptDebuggee {
       
    55     public final static int BKPT_LINE = 74;
       
    56     static ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
       
    57     static public String failReason = null;
       
    58 
       
    59     static void doit() throws Exception {
       
    60         System.out.println("Debugee: started!");
       
    61         String script =
       
    62                 "function f() {\r\n" +
       
    63                         " debugger;\r\n" +
       
    64                         " debugger;\r\n" +
       
    65                         "}\r\n" +
       
    66                         "f();";
       
    67         try {
       
    68             engine.eval(script);
       
    69         } catch (Exception ex) {
       
    70             failReason = "ScriptDebuggee failed: Exception in engine.eval(): "
       
    71                     + ex.toString();
       
    72             ex.printStackTrace();
       
    73         }
       
    74         System.out.println("Debugee: finished!"); // BKPT_LINE
       
    75     }
       
    76 
       
    77     public static void main(String[] args) throws Exception {
       
    78         doit();
       
    79     }
       
    80 }
       
    81 
       
    82 /********** test program **********/
       
    83 
       
    84 public class NashornPopFrameTest extends TestScaffold {
       
    85     static PrintStream out = System.out;
       
    86     static boolean breakpointReached = false;
       
    87     String debuggeeFailReason = null;
       
    88     ClassType targetClass;
       
    89     ThreadReference mainThread;
       
    90     BreakpointRequest bkptRequest;
       
    91 
       
    92     NashornPopFrameTest(String args[]) {
       
    93         super(args);
       
    94     }
       
    95 
       
    96     public static void main(String[] args)      throws Exception {
       
    97         NashornPopFrameTest nashornPopFrameTest = new NashornPopFrameTest(args);
       
    98         nashornPopFrameTest.startTests();
       
    99     }
       
   100 
       
   101     /********** test core **********/
       
   102 
       
   103     protected void runTests() throws Exception {
       
   104         /*
       
   105          * Get to the top of main() to determine targetClass and mainThread
       
   106          */
       
   107         BreakpointEvent bpe = startToMain("ScriptDebuggee");
       
   108         targetClass = (ClassType)bpe.location().declaringType();
       
   109         out.println("Agent: runTests: after startToMain()");
       
   110 
       
   111         mainThread = bpe.thread();
       
   112         EventRequestManager erm = vm().eventRequestManager();
       
   113 
       
   114         Location loc = findLocation(targetClass, ScriptDebuggee.BKPT_LINE);
       
   115 
       
   116         try {
       
   117             addListener(this);
       
   118         } catch (Exception ex){
       
   119             ex.printStackTrace();
       
   120             failure("Failed: Could not add listener");
       
   121             throw new Exception("NashornPopFrameTest: failed with Exception in AddListener");
       
   122         }
       
   123 
       
   124         pauseAtDebugger(vm());
       
   125         bkptRequest = erm.createBreakpointRequest(loc);
       
   126         bkptRequest.enable();
       
   127 
       
   128         vm().resume();
       
   129 
       
   130         try {
       
   131             listen(vm());
       
   132         } catch (Exception exp) {
       
   133             exp.printStackTrace();
       
   134             failure("Failed: Caught Exception while Listening");
       
   135             throw new Exception("NashornPopFrameTest: failed with Exception in listen()");
       
   136         }
       
   137 
       
   138         // Debugger continues to run until it receives a VMdisconnect event either because
       
   139         // the Debuggee crashed / got exception / finished successfully.
       
   140         while (!vmDisconnected) {
       
   141             try {
       
   142                 Thread.sleep(100);
       
   143             } catch (InterruptedException ee) {
       
   144             }
       
   145         }
       
   146 
       
   147         removeListener(this);
       
   148 
       
   149         if (breakpointReached) {
       
   150             if (debuggeeFailReason != null) {
       
   151                 failure(debuggeeFailReason);
       
   152             }
       
   153         } else {
       
   154             failure("Expected breakpoint in ScriptDebuggee:" +
       
   155                     ScriptDebuggee.BKPT_LINE + " was not reached");
       
   156         }
       
   157         if (testFailed) {
       
   158             throw new Exception("NashornPopFrameTest: failed");
       
   159         }
       
   160         out.println("NashornPopFrameTest: passed");
       
   161     }
       
   162 
       
   163     private static void pauseAtDebugger(VirtualMachine vm) throws AbsentInformationException {
       
   164         for (ReferenceType t : vm.allClasses()) pauseAtDebugger(t);
       
   165     }
       
   166 
       
   167     // Set a breakpoint in Nashorn internal DEBUGGER method.
       
   168     private static void pauseAtDebugger(ReferenceType t) throws AbsentInformationException {
       
   169         if (!t.name().endsWith(".ScriptRuntime")) {
       
   170             return;
       
   171         }
       
   172         for (Location l : t.allLineLocations()) {
       
   173             if (!l.method().name().equals("DEBUGGER")) continue;
       
   174             BreakpointRequest bkptReq = t.virtualMachine().eventRequestManager().createBreakpointRequest(l);
       
   175             out.println("Setting breakpoint for " + l);
       
   176             bkptReq.enable();
       
   177             break;
       
   178         }
       
   179     }
       
   180 
       
   181     private static void listen(VirtualMachine vm) throws Exception {
       
   182         EventQueue eventQueue = vm.eventQueue();
       
   183         EventSet es = eventQueue.remove();
       
   184         if (es != null) {
       
   185             handle(es);
       
   186         }
       
   187     }
       
   188 
       
   189     // Handle event when breakpoint is reached
       
   190     private static void handle(EventSet eventSet) throws Exception {
       
   191         out.println("Agent handle(): started");
       
   192         for (Event event : eventSet) {
       
   193             if (event instanceof BreakpointEvent) {
       
   194                 findFrameAndPop(event);
       
   195             }
       
   196         }
       
   197         eventSet.resume();
       
   198         out.println("Agent handle(): finished");
       
   199     }
       
   200 
       
   201     private static void findFrameAndPop(Event event) throws Exception {
       
   202         ThreadReference thread = ((BreakpointEvent) event).thread();
       
   203         out.println("Agent: handling Breakpoint " + " at " +
       
   204                 ((BreakpointEvent) event).location() +
       
   205                 " in thread: " + thread);
       
   206         StackFrame sf = findScriptFrame(thread);
       
   207         if (sf != null) {
       
   208             out.println("Thread Pop Frame on StackFrame = " + sf);
       
   209             thread.popFrames(sf);
       
   210         }
       
   211     }
       
   212 
       
   213     // Find stack frame whose method's declaring type name starts with
       
   214     // jdk.nashorn.internal.scripts.Script$ and return that frame
       
   215     private static StackFrame findScriptFrame(ThreadReference t) throws IncompatibleThreadStateException {
       
   216         for (int i = 0; i < t.frameCount(); i++) {
       
   217             StackFrame sf = t.frame(i);
       
   218             String typeName = sf.location().method().declaringType().name();
       
   219             if (typeName.startsWith("jdk.nashorn.internal.scripts.Script$")) {
       
   220                 out.println("Agent: in findScriptFrame: TypeName = " + typeName);
       
   221                 return sf;
       
   222             }
       
   223         }
       
   224         throw new RuntimeException("no script frame");
       
   225     }
       
   226 
       
   227     static int bkptCount = 0;
       
   228 
       
   229     /********** event handlers **********/
       
   230 
       
   231     public void breakpointReached(BreakpointEvent event) {
       
   232         ThreadReference thread = ((BreakpointEvent) event).thread();
       
   233         String locStr = "" + ((BreakpointEvent) event).location();
       
   234         out.println("Agent: BreakpointEvent #" + (bkptCount++) +
       
   235                 " at " + locStr + " in thread: " + thread);
       
   236         if (locStr.equals("ScriptDebuggee:" + ScriptDebuggee.BKPT_LINE)) {
       
   237             breakpointReached = true;
       
   238             Field failReasonField = targetClass.fieldByName("failReason");
       
   239             Value failReasonVal = targetClass.getValue(failReasonField);
       
   240             if (failReasonVal != null) {
       
   241                 debuggeeFailReason = ((StringReference)failReasonVal).value();
       
   242             }
       
   243             bkptRequest.disable();
       
   244         }
       
   245     }
       
   246 
       
   247     public void eventSetComplete(EventSet set) {
       
   248         set.resume();
       
   249     }
       
   250 
       
   251     public void vmDisconnected(VMDisconnectEvent event) {
       
   252         println("Agent: Got VMDisconnectEvent");
       
   253     }
       
   254 
       
   255 }