8212928: Assertion too strict in compiledVFrame::update_deferred_value on SPARC

Reviewed-by: kvn
This commit is contained in:
Richard Reingruber 2018-11-08 09:04:00 -08:00 committed by Vladimir Kozlov
parent 4187dff26a
commit e8fd8147a3
3 changed files with 233 additions and 1 deletions

View File

@ -102,7 +102,8 @@ void compiledVFrame::update_monitor(int index, MonitorInfo* val) {
}
void compiledVFrame::update_deferred_value(BasicType type, int index, jvalue value) {
assert(fr().is_deoptimized_frame(), "frame must be scheduled for deoptimization");
assert(fr().is_deoptimized_frame() || thread()->must_deopt_id() == fr().id(),
"frame must be scheduled for deoptimization");
GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred = thread()->deferred_locals();
jvmtiDeferredLocalVariableSet* locals = NULL;
if (deferred != NULL ) {

View File

@ -0,0 +1,191 @@
/*
* Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8212928
* @summary With NeedsDeoptSuspend == true the assertion in compiledVFrame::update_deferred_value() fails, because the frame is not deoptimized.
* @author Richard Reingruber richard DOT reingruber AT sap DOT com
*
* @library /test/lib
*
* @run build TestScaffold VMConnection TargetListener TargetAdapter
* @run main jdk.test.lib.FileInstaller compilerDirectives.json compilerDirectives.json
* @run compile -g SetLocalWhileThreadInNative.java
* @run driver SetLocalWhileThreadInNative -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+UnlockDiagnosticVMOptions -XX:CompilerDirectivesFile=compilerDirectives.json -XX:+PrintCompilation -XX:+PrintInlining
*/
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import jdk.test.lib.Asserts;
/********** target program **********/
class SetLocalWhileThreadInNativeTarget {
public static final String name = SetLocalWhileThreadInNativeTarget.class.getName();
public static FileInputStream fis;
public static int count;
public static int bytesRead;
// Let D (debugger) be a JVMTI agent that updates a local of a compiled frame F owned by
// thread T. In this test F corresponds to dontinline_testMethod.
//
// Issue: The VM thread executes an VM op on behalf of D to set the local in F. Doing so it
// requests the deoptimization of F and then calls compiledVFrame::update_deferred_value(),
// where frame::is_deoptimized_frame() returns false causing an assertion failure on SPARC where
// NeedsDeoptSuspend is true.
//
// Analysis: The deoptimization of F is requested, while T is in the native method
// java.io.FileInputStream::read0() and F is the direct caller of read0(). This is a special
// case with NeedsDeoptSuspend in frame::deoptimize(). Effectively the deoptimization is not
// done synchronously, instead T deoptimizes F at a later point upon return from the native
// method.
public static int dontinline_testMethod() {
int zero = 0;
int val = 0;
try {
val = fis.read(); // Will be inlined. Calls native method java.io.FileInputStream::read0()
count++;
} catch (IOException e) { /* ignored */ }
return val + zero;
}
public static void main(String[] args) {
System.out.println(name + " is up and running.");
fis = new FileInputStream(FileDescriptor.in);
bytesRead=0;
while (true) {
int val = dontinline_testMethod();
if (val == SetLocalWhileThreadInNative.STOP) {
System.out.println("Debuggee: received STOP message");
System.exit(0);
}
bytesRead++;
if ((bytesRead & ((1L << 14)-1)) == 0) {
System.out.println("Called test method " + bytesRead + " times");
}
}
}
}
/********** test program **********/
public class SetLocalWhileThreadInNative extends TestScaffold {
public static final int MESSAGE_COUNT = 10000;
public static final String MESSAGE = "0123456789";
public static final int MESSAGE_SIZE = MESSAGE.length();
public static final int TOTAL_BYTES = MESSAGE_COUNT * MESSAGE_SIZE;
public static final int STOP = 255;
ReferenceType mainClass;
ThreadReference mainThread;
SetLocalWhileThreadInNative (String args[]) {
super(args);
}
public static void main(String[] args)
throws Exception
{
new SetLocalWhileThreadInNative (args).startTests();
}
/********** test core **********/
protected void runTests()
throws Exception
{
String targetProgName = SetLocalWhileThreadInNativeTarget.class.getName();
String testName = getClass().getSimpleName();
// Start debuggee and obtain reference to main thread an main class
BreakpointEvent bpe = startToMain(targetProgName);
mainClass = bpe.location().declaringType();
mainThread = bpe.thread();
// Resume debuggee send some bytes
vm().resume();
OutputStream os = vm().process().getOutputStream();
byte[] ba = MESSAGE.getBytes();
for (int i = 0; i < MESSAGE_COUNT; i++) {
os.write(ba);
}
os.flush();
// Wait for the debugee to read all the bytes.
int bytesRead = 0;
Field bytesReadField = mainClass.fieldByName("bytesRead");
do {
bytesRead = ((PrimitiveValue)mainClass.getValue(bytesReadField)).intValue();
System.out.println("debugee has read " + bytesRead + " of " + TOTAL_BYTES);
Thread.sleep(500);
} while (bytesRead < TOTAL_BYTES);
// By now dontinline_testMethod() will be compiled. The debugee will be blocked in java.io.FileInputStream::read0().
// Now set local variable in dontinline_testMethod().
vm().suspend();
System.out.println("Debuggee Stack:");
List<StackFrame> stack_frames = mainThread.frames();
int i = 0;
for (StackFrame ff : stack_frames) {
System.out.println("frame[" + i++ +"]: " + ff.location().method());
}
StackFrame frame = mainThread.frame(2);
Asserts.assertEQ(frame.location().method().toString(), "SetLocalWhileThreadInNativeTarget.dontinline_testMethod()");
List<LocalVariable> localVars = frame.visibleVariables();
boolean changedLocal = false;
for (LocalVariable lv : localVars) {
if (lv.name().equals("zero")) {
frame.setValue(lv, vm().mirrorOf(0)); // triggers deoptimization!
changedLocal = true;
}
}
Asserts.assertTrue(changedLocal);
// signal stop
os.write(STOP);
os.flush();
// resume the target listening for events
listenUntilVMDisconnect();
// deal with results of test if anything has called failure("foo")
// testFailed will be true
if (!testFailed) {
println(testName + ": passed");
} else {
throw new Exception(testName + ": failed");
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
[
{
match: "*.*",
c1: {
// control inlining of method
// + force inline, - dont inline
inline : "-*.dontinline_*",
},
c2: {
// control inlining of method
// + force inline, - dont inline
inline : "-*.dontinline_*",
}
},
]