001/* 002 * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023/* 024 */ 025package com.oracle.graal.compiler.test.deopt; 026 027import jdk.internal.jvmci.code.*; 028import jdk.internal.jvmci.meta.*; 029 030import org.junit.*; 031 032import com.oracle.graal.compiler.test.*; 033import com.oracle.graal.nodes.*; 034import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; 035 036public final class MonitorDeoptTest extends GraalCompilerTest { 037 038 private enum State { 039 INITIAL, 040 RUNNING_GRAAL, 041 INVALIDATED, 042 RUNNING_INTERPRETER, 043 TERMINATED 044 } 045 046 private static class Monitor { 047 private volatile State state = State.INITIAL; 048 049 public synchronized void setState(State newState) { 050 state = newState; 051 notifyAll(); 052 } 053 054 public synchronized boolean tryUpdateState(State oldState, State newState) { 055 if (state == oldState) { 056 state = newState; 057 notifyAll(); 058 return true; 059 } else { 060 return false; 061 } 062 } 063 064 public synchronized void waitState(State targetState) throws InterruptedException { 065 while (state != targetState) { 066 wait(); 067 } 068 } 069 070 public synchronized State getState() { 071 return state; 072 } 073 074 public synchronized void invalidate(InstalledCode code) { 075 state = State.INVALIDATED; 076 code.invalidate(); 077 } 078 } 079 080 public static boolean test(Monitor monitor) { 081 // initially, we're running as Graal compiled code 082 monitor.setState(State.RUNNING_GRAAL); 083 084 for (;;) { 085 // wait for the compiled code to be invalidated 086 if (monitor.tryUpdateState(State.INVALIDATED, State.RUNNING_INTERPRETER)) { 087 break; 088 } 089 } 090 091 for (int i = 0; i < 500; i++) { 092 // wait for the control thread to send the TERMINATED signal 093 if (monitor.getState() == State.TERMINATED) { 094 return true; 095 } 096 097 try { 098 Thread.sleep(10); 099 } catch (InterruptedException e) { 100 } 101 } 102 103 // we're running for more than 5 s in the interpreter 104 // probably the control thread is deadlocked 105 return false; 106 } 107 108 private static LoopBeginNode findFirstLoop(StructuredGraph graph) { 109 FixedNode node = graph.start(); 110 for (;;) { 111 if (node instanceof LoopBeginNode) { 112 return (LoopBeginNode) node; 113 } else if (node instanceof FixedWithNextNode) { 114 node = ((FixedWithNextNode) node).next(); 115 } else if (node instanceof AbstractEndNode) { 116 node = ((AbstractEndNode) node).merge(); 117 } else { 118 Assert.fail(String.format("unexpected node %s in graph of test method", node)); 119 } 120 } 121 } 122 123 /** 124 * Remove the safepoint from the first loop in the test method, so only the safepoints on 125 * MonitorEnter and MonitorExit remain in the loop. That way, we can make sure it deopts inside 126 * the MonitorEnter by invalidating the code while holding the lock. 127 */ 128 private static void removeLoopSafepoint(StructuredGraph graph) { 129 LoopBeginNode loopBegin = findFirstLoop(graph); 130 for (LoopEndNode end : loopBegin.loopEnds()) { 131 end.disableSafepoint(); 132 } 133 } 134 135 @Test 136 public void run0() throws Throwable { 137 ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test"); 138 139 StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES); 140 removeLoopSafepoint(graph); 141 142 CompilationResult compilationResult = compile(javaMethod, graph); 143 final InstalledCode installedCode = getProviders().getCodeCache().setDefaultMethod(javaMethod, compilationResult); 144 145 final Monitor monitor = new Monitor(); 146 147 Thread controlThread = new Thread(new Runnable() { 148 149 public void run() { 150 try { 151 // wait for the main thread to start 152 monitor.waitState(State.RUNNING_GRAAL); 153 154 // invalidate the compiled code while holding the lock 155 // at this point, the compiled method hangs in a MonitorEnter 156 monitor.invalidate(installedCode); 157 158 // wait for the main thread to continue running in the interpreter 159 monitor.waitState(State.RUNNING_INTERPRETER); 160 161 // terminate the main thread 162 monitor.setState(State.TERMINATED); 163 } catch (InterruptedException e) { 164 } 165 } 166 }); 167 168 controlThread.start(); 169 170 boolean result = test(monitor); 171 Assert.assertTrue(result); 172 } 173}