diff --git a/1417266.patch b/1417266.patch new file mode 100644 index 0000000..82a5b16 --- /dev/null +++ b/1417266.patch @@ -0,0 +1,130 @@ + +# HG changeset patch +# User roland +# Date 1487208397 28800 +# Node ID 35db0413819a18edd6718dd42e7536182c42aa8b +# Parent ac559f3ccca81de373f18ac7c4b2d813d0278920 +8174164: SafePointNode::_replaced_nodes breaks with irreducible loops +Reviewed-by: kvn + +diff -r ac559f3ccca8 -r 35db0413819a src/share/vm/opto/callnode.hpp +--- openjdk/hotspot/src/share/vm/opto/callnode.hpp Wed Feb 15 11:14:45 2017 +0100 ++++ openjdk/hotspot/src/share/vm/opto/callnode.hpp Wed Feb 15 17:26:37 2017 -0800 +@@ -452,8 +452,8 @@ + void delete_replaced_nodes() { + _replaced_nodes.reset(); + } +- void apply_replaced_nodes() { +- _replaced_nodes.apply(this); ++ void apply_replaced_nodes(uint idx) { ++ _replaced_nodes.apply(this, idx); + } + void merge_replaced_nodes_with(SafePointNode* sfpt) { + _replaced_nodes.merge_with(sfpt->_replaced_nodes); +# I was informed that this hunk is not necessary in jdk8 +#diff -r ac559f3ccca8 -r 35db0413819a src/share/vm/opto/library_call.cpp +#--- openjdk/hotspot/src/share/vm/opto/library_call.cpp Wed Feb 15 11:14:45 2017 +0100 +#+++ openjdk/hotspot/src/share/vm/opto/library_call.cpp Wed Feb 15 17:26:37 2017 -0800 +#@@ -277,7 +277,8 @@ +# AllocateArrayNode* tightly_coupled_allocation(Node* ptr, +# RegionNode* slow_region); +# JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); +#- void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); +#+ void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp, +#+ uint new_idx); +# +# typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; +# MemNode::MemOrd access_kind_to_memord_LS(AccessKind access_kind, bool is_store); +#@@ -4882,7 +4883,8 @@ +# // deoptimize. This is possible because tightly_coupled_allocation() +# // guarantees there's no observer of the allocated array at this point +# // and the control flow is simple enough. +#-void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp) { +#+void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, +#+ int saved_reexecute_sp, uint new_idx) { +# if (saved_jvms != NULL && !stopped()) { +# assert(alloc != NULL, "only with a tightly coupled allocation"); +# // restore JVM state to the state at the arraycopy +#@@ -4891,7 +4893,7 @@ +# assert(saved_jvms->map()->i_o() == map()->i_o(), "IO state changed?"); +# // If we've improved the types of some nodes (null check) while +# // emitting the guards, propagate them to the current state +#- map()->replaced_nodes().apply(saved_jvms->map()); +#+ map()->replaced_nodes().apply(saved_jvms->map(), new_idx); +# set_jvms(saved_jvms); +# _reexecute_sp = saved_reexecute_sp; +# +#@@ -4949,6 +4951,7 @@ +# Node* dest_offset = argument(3); // type: int +# Node* length = argument(4); // type: int +# +#+ uint new_idx = C->unique(); +# +# // Check for allocation before we add nodes that would confuse +# // tightly_coupled_allocation() +#@@ -5164,7 +5167,7 @@ +# } +# } +# +#- arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp); +#+ arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp, new_idx); +# +# if (stopped()) { +# return true; +diff -r ac559f3ccca8 -r 35db0413819a src/share/vm/opto/parse1.cpp +--- openjdk/hotspot/src/share/vm/opto/parse1.cpp Wed Feb 15 11:14:45 2017 +0100 ++++ openjdk/hotspot/src/share/vm/opto/parse1.cpp Wed Feb 15 17:26:37 2017 -0800 +@@ -1086,7 +1086,7 @@ + kit.make_dtrace_method_exit(method()); + } + if (_replaced_nodes_for_exceptions) { +- kit.map()->apply_replaced_nodes(); ++ kit.map()->apply_replaced_nodes(_new_idx); + } + // Done with exception-path processing. + ex_map = kit.make_exception_state(ex_oop); +@@ -1107,7 +1107,7 @@ + _exits.add_exception_state(ex_map); + } + } +- _exits.map()->apply_replaced_nodes(); ++ _exits.map()->apply_replaced_nodes(_new_idx); + } + + //-----------------------------create_entry_map------------------------------- +diff -r ac559f3ccca8 -r 35db0413819a src/share/vm/opto/replacednodes.cpp +--- openjdk/hotspot/src/share/vm/opto/replacednodes.cpp Wed Feb 15 11:14:45 2017 +0100 ++++ openjdk/hotspot/src/share/vm/opto/replacednodes.cpp Wed Feb 15 17:26:37 2017 -0800 +@@ -92,13 +92,17 @@ + } + + // Perfom node replacement (used when returning to caller) +-void ReplacedNodes::apply(Node* n) { ++void ReplacedNodes::apply(Node* n, uint idx) { + if (is_empty()) { + return; + } + for (int i = 0; i < _replaced_nodes->length(); i++) { + ReplacedNode replaced = _replaced_nodes->at(i); +- n->replace_edge(replaced.initial(), replaced.improved()); ++ // Only apply if improved node was created in a callee to avoid ++ // issues with irreducible loops in the caller ++ if (replaced.improved()->_idx >= idx) { ++ n->replace_edge(replaced.initial(), replaced.improved()); ++ } + } + } + +diff -r ac559f3ccca8 -r 35db0413819a src/share/vm/opto/replacednodes.hpp +--- openjdk/hotspot/src/share/vm/opto/replacednodes.hpp Wed Feb 15 11:14:45 2017 +0100 ++++ openjdk/hotspot/src/share/vm/opto/replacednodes.hpp Wed Feb 15 17:26:37 2017 -0800 +@@ -71,7 +71,7 @@ + void record(Node* initial, Node* improved); + void transfer_from(const ReplacedNodes& other, uint idx); + void reset(); +- void apply(Node* n); ++ void apply(Node* n, uint idx); + void merge_with(const ReplacedNodes& other); + bool is_empty() const; + void dump(outputStream *st) const; + diff --git a/8153711-pr3313-rh1284948.patch b/8153711-pr3313-rh1284948.patch new file mode 100644 index 0000000..b93fa06 --- /dev/null +++ b/8153711-pr3313-rh1284948.patch @@ -0,0 +1,669 @@ +# HG changeset patch +# User sgehwolf +# Date 1458555849 -3600 +# Mon Mar 21 11:24:09 2016 +0100 +# Node ID 9f6a0864a734ae3fd0eb198768db7cdee53ba0ed +# Parent 1179be40f1e3b59a890e96a5a9d3ff6fc18a2846 +8153711, PR3313: [REDO] JDWP: Memory Leak: GlobalRefs never deleted when processing invokeMethod command +Summary: Delete global references in invoker_completeInvokeRequest() +Reviewed-by: sspitsyn, dsamersoff + +diff --git a/src/share/back/invoker.c b/src/share/back/invoker.c +--- openjdk/jdk/src/share/back/invoker.c ++++ openjdk/jdk/src/share/back/invoker.c +@@ -211,6 +211,62 @@ + return error; + } + ++/* ++ * Delete saved global references - if any - for: ++ * - a potentially thrown Exception ++ * - a returned refernce/array value ++ * See invoker_doInvoke() and invoke* methods where global references ++ * are being saved. ++ */ ++static void ++deletePotentiallySavedGlobalRefs(JNIEnv *env, InvokeRequest *request) ++{ ++ /* Delete potentially saved return value */ ++ if ((request->invokeType == INVOKE_CONSTRUCTOR) || ++ (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) || ++ (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) { ++ if (request->returnValue.l != NULL) { ++ tossGlobalRef(env, &(request->returnValue.l)); ++ } ++ } ++ /* Delete potentially saved exception */ ++ if (request->exception != NULL) { ++ tossGlobalRef(env, &(request->exception)); ++ } ++} ++ ++/* ++ * Delete global argument references from the request which got put there before a ++ * invoke request was carried out. See fillInvokeRequest(). ++ */ ++static void ++deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request) ++{ ++ void *cursor; ++ jint argIndex = 0; ++ jvalue *argument = request->arguments; ++ jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor); ++ ++ if (request->clazz != NULL) { ++ tossGlobalRef(env, &(request->clazz)); ++ } ++ if (request->instance != NULL) { ++ tossGlobalRef(env, &(request->instance)); ++ } ++ /* Delete global argument references */ ++ while (argIndex < request->argumentCount) { ++ if ((argumentTag == JDWP_TAG(OBJECT)) || ++ (argumentTag == JDWP_TAG(ARRAY))) { ++ if (argument->l != NULL) { ++ tossGlobalRef(env, &(argument->l)); ++ } ++ } ++ argument++; ++ argIndex++; ++ argumentTag = nextArgumentTypeTag(&cursor); ++ } ++} ++ + static jvmtiError + fillInvokeRequest(JNIEnv *env, InvokeRequest *request, + jbyte invokeType, jbyte options, jint id, +@@ -320,6 +376,8 @@ + invokeConstructor(JNIEnv *env, InvokeRequest *request) + { + jobject object; ++ ++ JDI_ASSERT_MSG(request->clazz, "Request clazz null"); + object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz, + request->method, + request->arguments); +@@ -336,6 +394,7 @@ + case JDWP_TAG(OBJECT): + case JDWP_TAG(ARRAY): { + jobject object; ++ JDI_ASSERT_MSG(request->clazz, "Request clazz null"); + object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env, + request->clazz, + request->method, +@@ -424,6 +483,7 @@ + case JDWP_TAG(OBJECT): + case JDWP_TAG(ARRAY): { + jobject object; ++ JDI_ASSERT_MSG(request->instance, "Request instance null"); + object = JNI_FUNC_PTR(env,CallObjectMethodA)(env, + request->instance, + request->method, +@@ -511,6 +571,8 @@ + case JDWP_TAG(OBJECT): + case JDWP_TAG(ARRAY): { + jobject object; ++ JDI_ASSERT_MSG(request->clazz, "Request clazz null"); ++ JDI_ASSERT_MSG(request->instance, "Request instance null"); + object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env, + request->instance, + request->clazz, +@@ -607,6 +669,8 @@ + JNIEnv *env; + jboolean startNow; + InvokeRequest *request; ++ jbyte options; ++ jbyte invokeType; + + JDI_ASSERT(thread); + +@@ -623,6 +687,9 @@ + if (startNow) { + request->started = JNI_TRUE; + } ++ options = request->options; ++ invokeType = request->invokeType; ++ + debugMonitorExit(invokerLock); + + if (!startNow) { +@@ -637,7 +704,7 @@ + + JNI_FUNC_PTR(env,ExceptionClear)(env); + +- switch (request->invokeType) { ++ switch (invokeType) { + case INVOKE_CONSTRUCTOR: + invokeConstructor(env, request); + break; +@@ -645,7 +712,7 @@ + invokeStatic(env, request); + break; + case INVOKE_INSTANCE: +- if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) { ++ if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) { + invokeNonvirtual(env, request); + } else { + invokeVirtual(env, request); +@@ -723,12 +790,23 @@ + } + + /* ++ * At this time, there's no need to retain global references on ++ * arguments since the reply is processed. No one will deal with ++ * this request ID anymore, so we must call deleteGlobalArgumentRefs(). ++ * ++ * We cannot delete saved exception or return value references ++ * since otherwise a deleted handle would escape when writing ++ * the response to the stream. Instead, we clean those refs up ++ * after writing the respone. ++ */ ++ deleteGlobalArgumentRefs(env, request); ++ ++ /* + * Give up the lock before I/O operation + */ + debugMonitorExit(invokerLock); + eventHandler_unlock(); + +- + if (!detached) { + outStream_initReply(&out, id); + (void)outStream_writeValue(env, &out, tag, returnValue); +@@ -736,6 +814,16 @@ + (void)outStream_writeObjectRef(env, &out, exc); + outStream_sendReply(&out); + } ++ ++ /* ++ * Delete potentially saved global references of return value ++ * and exception ++ */ ++ eventHandler_lock(); // for proper lock order ++ debugMonitorEnter(invokerLock); ++ deletePotentiallySavedGlobalRefs(env, request); ++ debugMonitorExit(invokerLock); ++ eventHandler_unlock(); + } + + jboolean +diff --git a/test/com/sun/jdi/oom/@debuggeeVMOptions b/test/com/sun/jdi/oom/@debuggeeVMOptions +new file mode 100644 +--- /dev/null ++++ openjdk/jdk/test/com/sun/jdi/oom/@debuggeeVMOptions +@@ -0,0 +1,1 @@ ++-Xmx40m +\ No newline at end of file +diff --git a/test/com/sun/jdi/oom/OomDebugTest.java b/test/com/sun/jdi/oom/OomDebugTest.java +new file mode 100644 +--- /dev/null ++++ openjdk/jdk/test/com/sun/jdi/oom/OomDebugTest.java +@@ -0,0 +1,417 @@ ++/* ++ * Copyright (c) 2016 Red Hat Inc. ++ * ++ * 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 8153711 ++ * @summary JDWP: Memory Leak (global references not deleted after invokeMethod). ++ * ++ * @author Severin Gehwolf ++ * ++ * @library .. ++ * @run build TestScaffold VMConnection TargetListener TargetAdapter ++ * @run compile -g OomDebugTest.java ++ * @run shell OomDebugTestSetup.sh ++ * @run main OomDebugTest OomDebugTestTarget test1 ++ * @run main OomDebugTest OomDebugTestTarget test2 ++ * @run main OomDebugTest OomDebugTestTarget test3 ++ * @run main OomDebugTest OomDebugTestTarget test4 ++ * @run main OomDebugTest OomDebugTestTarget test5 ++ */ ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.FileNotFoundException; ++import java.io.FileOutputStream; ++import java.io.IOException; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Properties; ++import java.util.Set; ++ ++import com.sun.jdi.ArrayReference; ++import com.sun.jdi.ArrayType; ++import com.sun.jdi.ClassType; ++import com.sun.jdi.Field; ++import com.sun.jdi.InvocationException; ++import com.sun.jdi.Method; ++import com.sun.jdi.ObjectReference; ++import com.sun.jdi.ReferenceType; ++import com.sun.jdi.StackFrame; ++import com.sun.jdi.VMOutOfMemoryException; ++import com.sun.jdi.Value; ++import com.sun.jdi.event.BreakpointEvent; ++import com.sun.jdi.event.ExceptionEvent; ++ ++/***************** Target program **********************/ ++ ++class OomDebugTestTarget { ++ ++ OomDebugTestTarget() { ++ System.out.println("DEBUG: invoked constructor"); ++ } ++ static class FooCls { ++ @SuppressWarnings("unused") ++ private byte[] bytes = new byte[3000000]; ++ }; ++ ++ FooCls fooCls = new FooCls(); ++ byte[] byteArray = new byte[0]; ++ ++ void testMethod(FooCls foo) { ++ System.out.println("DEBUG: invoked 'void testMethod(FooCls)', foo == " + foo); ++ } ++ ++ void testPrimitive(byte[] foo) { ++ System.out.println("DEBUG: invoked 'void testPrimitive(byte[])', foo == " + foo); ++ } ++ ++ byte[] testPrimitiveArrRetval() { ++ System.out.println("DEBUG: invoked 'byte[] testPrimitiveArrRetval()'"); ++ return new byte[3000000]; ++ } ++ ++ FooCls testFooClsRetval() { ++ System.out.println("DEBUG: invoked 'FooCls testFooClsRetval()'"); ++ return new FooCls(); ++ } ++ ++ public void entry() {} ++ ++ public static void main(String[] args){ ++ System.out.println("DEBUG: OomDebugTestTarget.main"); ++ new OomDebugTestTarget().entry(); ++ } ++} ++ ++/***************** Test program ************************/ ++ ++public class OomDebugTest extends TestScaffold { ++ ++ private static final String[] ALL_TESTS = new String[] { ++ "test1", "test2", "test3", "test4", "test5" ++ }; ++ private static final Set ALL_TESTS_SET = new HashSet(); ++ static { ++ ALL_TESTS_SET.addAll(Arrays.asList(ALL_TESTS)); ++ } ++ private static final String TEST_CLASSES = System.getProperty("test.classes", "."); ++ private static final File RESULT_FILE = new File(TEST_CLASSES, "results.properties"); ++ private static final String LAST_TEST = ALL_TESTS[ALL_TESTS.length - 1]; ++ private ReferenceType targetClass; ++ private ObjectReference thisObject; ++ private int failedTests; ++ private final String testMethod; ++ ++ public OomDebugTest(String[] args) { ++ super(args); ++ if (args.length != 2) { ++ throw new RuntimeException("Wrong number of command-line arguments specified."); ++ } ++ this.testMethod = args[1]; ++ } ++ ++ @Override ++ protected void runTests() throws Exception { ++ try { ++ addListener(new TargetAdapter() { ++ ++ @Override ++ public void exceptionThrown(ExceptionEvent event) { ++ String name = event.exception().referenceType().name(); ++ System.err.println("DEBUG: Exception thrown in debuggee was: " + name); ++ } ++ }); ++ /* ++ * Get to the top of entry() ++ * to determine targetClass and mainThread ++ */ ++ BreakpointEvent bpe = startTo("OomDebugTestTarget", "entry", "()V"); ++ targetClass = bpe.location().declaringType(); ++ ++ mainThread = bpe.thread(); ++ ++ StackFrame frame = mainThread.frame(0); ++ thisObject = frame.thisObject(); ++ java.lang.reflect.Method m = findTestMethod(); ++ m.invoke(this); ++ } catch (NoSuchMethodException e) { ++ e.printStackTrace(); ++ failure(); ++ } catch (SecurityException e) { ++ e.printStackTrace(); ++ failure(); ++ } ++ /* ++ * resume the target, listening for events ++ */ ++ listenUntilVMDisconnect(); ++ } ++ ++ private java.lang.reflect.Method findTestMethod() ++ throws NoSuchMethodException, SecurityException { ++ return OomDebugTest.class.getDeclaredMethod(testMethod); ++ } ++ ++ private void failure() { ++ failedTests++; ++ } ++ ++ /* ++ * Test case: Object reference as method parameter. ++ */ ++ @SuppressWarnings("unused") // called via reflection ++ private void test1() throws Exception { ++ System.out.println("DEBUG: ------------> Running test1"); ++ try { ++ Field field = targetClass.fieldByName("fooCls"); ++ ClassType clsType = (ClassType)field.type(); ++ Method constructor = getConstructorForClass(clsType); ++ for (int i = 0; i < 15; i++) { ++ @SuppressWarnings({ "rawtypes", "unchecked" }) ++ ObjectReference objRef = clsType.newInstance(mainThread, ++ constructor, ++ new ArrayList(0), ++ ObjectReference.INVOKE_NONVIRTUAL); ++ if (objRef.isCollected()) { ++ System.out.println("DEBUG: Object got GC'ed before we can use it. NO-OP."); ++ continue; ++ } ++ invoke("testMethod", "(LOomDebugTestTarget$FooCls;)V", objRef); ++ } ++ } catch (InvocationException e) { ++ handleFailure(e); ++ } ++ } ++ ++ /* ++ * Test case: Array reference as method parameter. ++ */ ++ @SuppressWarnings("unused") // called via reflection ++ private void test2() throws Exception { ++ System.out.println("DEBUG: ------------> Running test2"); ++ try { ++ Field field = targetClass.fieldByName("byteArray"); ++ ArrayType arrType = (ArrayType)field.type(); ++ ++ for (int i = 0; i < 15; i++) { ++ ArrayReference byteArrayVal = arrType.newInstance(3000000); ++ if (byteArrayVal.isCollected()) { ++ System.out.println("DEBUG: Object got GC'ed before we can use it. NO-OP."); ++ continue; ++ } ++ invoke("testPrimitive", "([B)V", byteArrayVal); ++ } ++ } catch (VMOutOfMemoryException e) { ++ defaultHandleOOMFailure(e); ++ } ++ } ++ ++ /* ++ * Test case: Array reference as return value. ++ */ ++ @SuppressWarnings("unused") // called via reflection ++ private void test3() throws Exception { ++ System.out.println("DEBUG: ------------> Running test3"); ++ try { ++ for (int i = 0; i < 15; i++) { ++ invoke("testPrimitiveArrRetval", ++ "()[B", ++ Collections.EMPTY_LIST, ++ vm().mirrorOfVoid()); ++ } ++ } catch (InvocationException e) { ++ handleFailure(e); ++ } ++ } ++ ++ /* ++ * Test case: Object reference as return value. ++ */ ++ @SuppressWarnings("unused") // called via reflection ++ private void test4() throws Exception { ++ System.out.println("DEBUG: ------------> Running test4"); ++ try { ++ for (int i = 0; i < 15; i++) { ++ invoke("testFooClsRetval", ++ "()LOomDebugTestTarget$FooCls;", ++ Collections.EMPTY_LIST, ++ vm().mirrorOfVoid()); ++ } ++ } catch (InvocationException e) { ++ handleFailure(e); ++ } ++ } ++ ++ /* ++ * Test case: Constructor ++ */ ++ @SuppressWarnings({ "unused", "unchecked", "rawtypes" }) // called via reflection ++ private void test5() throws Exception { ++ System.out.println("DEBUG: ------------> Running test5"); ++ try { ++ ClassType type = (ClassType)thisObject.type(); ++ for (int i = 0; i < 15; i++) { ++ type.newInstance(mainThread, ++ findMethod(targetClass, "", "()V"), ++ new ArrayList(0), ++ ObjectReference.INVOKE_NONVIRTUAL); ++ } ++ } catch (InvocationException e) { ++ handleFailure(e); ++ } ++ } ++ ++ private Method getConstructorForClass(ClassType clsType) { ++ List methods = clsType.methodsByName(""); ++ if (methods.size() != 1) { ++ throw new RuntimeException("FAIL. Expected only one, the default, constructor"); ++ } ++ return methods.get(0); ++ } ++ ++ private void handleFailure(InvocationException e) { ++ // There is no good way to see the OOME diagnostic message in the target since the ++ // TestScaffold might throw an exception while trying to print the stack trace. I.e ++ // it might get a a VMDisconnectedException before the stack trace printing finishes. ++ System.err.println("FAILURE: InvocationException thrown. Trying to determine cause..."); ++ defaultHandleOOMFailure(e); ++ } ++ ++ private void defaultHandleOOMFailure(Exception e) { ++ e.printStackTrace(); ++ failure(); ++ } ++ ++ @SuppressWarnings({ "rawtypes", "unchecked" }) ++ void invoke(String methodName, String methodSig, Value value) ++ throws Exception { ++ List args = new ArrayList(1); ++ args.add(value); ++ invoke(methodName, methodSig, args, value); ++ } ++ ++ void invoke(String methodName, ++ String methodSig, ++ @SuppressWarnings("rawtypes") List args, ++ Value value) throws Exception { ++ Method method = findMethod(targetClass, methodName, methodSig); ++ if ( method == null) { ++ failure("FAILED: Can't find method: " ++ + methodName + " for class = " + targetClass); ++ return; ++ } ++ invoke(method, args, value); ++ } ++ ++ @SuppressWarnings({ "rawtypes", "unchecked" }) ++ void invoke(Method method, List args, Value value) throws Exception { ++ thisObject.invokeMethod(mainThread, method, args, 0); ++ System.out.println("DEBUG: Done invoking method via debugger."); ++ } ++ ++ Value fieldValue(String fieldName) { ++ Field field = targetClass.fieldByName(fieldName); ++ return thisObject.getValue(field); ++ } ++ ++ // Determine the pass/fail status on some heuristic and don't fail the ++ // test if < 3 of the total number of tests (currently 5) fail. This also ++ // has the nice side effect that all tests are first attempted and only ++ // all tests ran an overall pass/fail status is determined. ++ private static void determineOverallTestStatus(OomDebugTest oomTest) ++ throws IOException, FileNotFoundException { ++ Properties resultProps = new Properties(); ++ if (!RESULT_FILE.exists()) { ++ RESULT_FILE.createNewFile(); ++ } ++ FileInputStream fin = null; ++ try { ++ fin = new FileInputStream(RESULT_FILE); ++ resultProps.load(fin); ++ resultProps.put(oomTest.testMethod, ++ Integer.toString(oomTest.failedTests)); ++ } finally { ++ if (fin != null) { ++ fin.close(); ++ } ++ } ++ System.out.println("DEBUG: Finished running test '" ++ + oomTest.testMethod + "'."); ++ if (LAST_TEST.equals(oomTest.testMethod)) { ++ System.out.println("DEBUG: Determining overall test status."); ++ Set actualTestsRun = new HashSet(); ++ int totalTests = ALL_TESTS.length; ++ int failedTests = 0; ++ for (Object key: resultProps.keySet()) { ++ actualTestsRun.add((String)key); ++ Object propVal = resultProps.get(key); ++ int value = Integer.parseInt((String)propVal); ++ failedTests += value; ++ } ++ if (!ALL_TESTS_SET.equals(actualTestsRun)) { ++ String errorMsg = "Test failed! Expected to run tests '" ++ + ALL_TESTS_SET + "', but only these were run '" ++ + actualTestsRun + "'"; ++ throw new RuntimeException(errorMsg); ++ } ++ if (failedTests >= 3) { ++ String errorMsg = "Test failed. Expected < 3 sub-tests to fail " ++ + "for a pass. Got " + failedTests ++ + " failed tests out of " + totalTests + "."; ++ throw new RuntimeException(errorMsg); ++ } ++ RESULT_FILE.delete(); ++ System.out.println("All " + totalTests + " tests passed."); ++ } else { ++ System.out.println("DEBUG: More tests to run. Continuing."); ++ FileOutputStream fout = null; ++ try { ++ fout = new FileOutputStream(RESULT_FILE); ++ resultProps.store(fout, "Storing results after test " ++ + oomTest.testMethod); ++ } finally { ++ if (fout != null) { ++ fout.close(); ++ } ++ } ++ } ++ } ++ ++ public static void main(String[] args) throws Exception { ++ System.setProperty("test.vm.opts", "-Xmx40m"); // Set debuggee VM option ++ OomDebugTest oomTest = new OomDebugTest(args); ++ try { ++ oomTest.startTests(); ++ } catch (Throwable e) { ++ System.out.println("DEBUG: Got exception for test run. " + e); ++ e.printStackTrace(); ++ oomTest.failure(); ++ } ++ determineOverallTestStatus(oomTest); ++ } ++ ++} +diff --git a/test/com/sun/jdi/oom/OomDebugTestSetup.sh b/test/com/sun/jdi/oom/OomDebugTestSetup.sh +new file mode 100644 +--- /dev/null ++++ openjdk/jdk/test/com/sun/jdi/oom/OomDebugTestSetup.sh +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# ++# Copyright (c) 2016 Red Hat Inc. ++# 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. ++# ++ ++ ++if [ "${TESTSRC}" = "" ] ++then ++ echo "TESTSRC not set. Test cannot execute. Failed." ++ exit 1 ++fi ++echo "TESTSRC=${TESTSRC}" ++ ++if [ "${TESTJAVA}" = "" ] ++then ++ echo "TESTJAVA not set. Test cannot execute. Failed." ++ exit 1 ++fi ++echo "TESTJAVA=${TESTJAVA}" ++ ++if [ "${TESTCLASSES}" = "" ] ++then ++ echo "TESTCLASSES not set. Test cannot execute. Failed." ++ exit 1 ++fi ++ ++cp ${TESTSRC}/@debuggeeVMOptions ${TESTCLASSES}/ diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index c7eec17..5dfff61 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -801,7 +801,7 @@ Obsoletes: java-1.7.0-openjdk-accessibility%1 Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever} -Release: 3.%{buildver}%{?dist} +Release: 4.%{buildver}%{?dist} # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons, # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -929,6 +929,11 @@ Patch526: 6260348-pr3066.patch # S8162384, PR3122, RH1358661: Performance regression: bimorphic inlining may be bypassed by type speculation Patch532: 8162384-pr3122-rh1358661.patch +# Patches upstream and appearing in 8u152 +# 8153711, PR3313, RH1284948: [REDO] JDWP: Memory Leak: GlobalRefs never deleted when processing invokeMethod command +Patch535: 8153711-pr3313-rh1284948.patch +Patch536: 1417266.patch + # Patches ineligible for 8u # 8043805: Allow using a system-installed libjpeg Patch201: system-libjpeg.patch @@ -1278,6 +1283,8 @@ sh %{SOURCE12} %patch528 %patch532 %patch533 +%patch535 +%patch536 # RHEL-only patches %if 0%{?rhel} @@ -1503,6 +1510,7 @@ done # Make sure gdb can do a backtrace based on line numbers on libjvm.so gdb -q "$JAVA_HOME/bin/java" < - 1:1.8.0.121-4.b14 +- added Patch535 and 526 +- tweeked debugsymbols check for sigill + * Wed Jan 25 2017 jvanek - 1:1.8.0.121-2.b14 - revertrd patch535, excludeECDHE-1415137.patch and related changes - issue casued by nss, see rhbz#1415137 c#35