Mercurial > hg > graal-jvmci-8
changeset 23660:b5f3a471e646
Merge.
line wrap: on
line diff
--- a/.hgtags Tue May 31 08:05:44 2016 +0200 +++ b/.hgtags Wed Jun 01 00:11:44 2016 +0200 @@ -566,6 +566,7 @@ b517d3a9aebf0fee64808f9a7c0ef8e0b82d5ed3 jdk8u31-b31 15d8108258cb60a58bdd03b9ff8e77dd6727a804 jdk8u31-b32 26b1dc6891c4fae03575a9090f7d04bd631d9164 jdk8u31-b33 +70e73f8f43fc71c0629253e22121c974bfd79b86 jdk8u31-b34 1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11 @@ -667,6 +668,9 @@ 9a70cba6a3c3e44486f9c199d03a16b2b09d0a13 jdk8u51-b15 3639e38bd73f5efa8ce092f0a745bb0c90759575 jdk8u51-b16 20bad8c6c7b406c3603b4e22b15cd990840a9d62 jdk8u51-b31 +e51afd2a1fc17de59ff3c79003210a40a28ac960 jdk8u51-b32 +b2427357cc98aeb2716ee2e89e733794afb4057b jdk8u51-b33 +4b722db6d38583ee3e71c43d9996bf1ebb8a412e jdk8u51-b34 d9349fa8822336e0244da0a8448f3e6b2d62741d jdk8u60-b00 d9349fa8822336e0244da0a8448f3e6b2d62741d hs25.60-b00 ebf89088c08ab0508b9002b48dd3d68a340259af hs25.60-b01 @@ -720,6 +724,8 @@ 6b4ea38c01bd9cc86d0aa8926f4855ff6ee365ee jdk8u60-b25 6a6759372807f49aa7a66ddc36aa91d6648d2097 jdk8u60-b26 10ad4b9d79f98fa3545c88a342a68a80d198b808 jdk8u60-b27 +1f646daf0d673b0925da1ed7809d6bd097388ece jdk8u60-b31 +9bf9a733246b5e89986233f42a8e00c798ca703f jdk8u60-b32 0219ab69f00782e5c49687e2fa75138a7ffddea1 jdk8u52-b06 9b6f44853eed8caba935915c7e710c546b205c8e jdk8u52-b07 0219ab69f00782e5c49687e2fa75138a7ffddea1 jdk8u65-b00 @@ -755,6 +761,87 @@ 9f7f29ff487ae023ca1f697445004a532751b0d2 jdk8u66-b14 5b67af3317bce1f940c5dc1535411a1002bed6c1 jdk8u66-b15 4bbf0e9196f2786e0bc4f17664e2533808d944bf jdk8u66-b16 +a6f2a7ba281291f5dab79fa494f7cfaa6232c88b jdk8u66-b17 +9ae2a5adabba97d9ebf79e13b325f1ff368ce014 jdk8u66-b18 +527f62b70faee4a0c15f365def024b87012e6934 jdk8u66-b31 +d8be40462cfb6de441818aec8c30e03077189010 jdk8u66-b32 +6a0b19c56d797c2975f0cf505190e8f5d69b0b7a jdk8u66-b33 +3d55b1055c782375e39ebbddba2887379bc3531c jdk8u66-b34 +95b0e04287fb443a4eee64504e0f18bc324c7abd jdk8u66-b35 +dce99debdba26def128cd8b2d3eae93d7d789ee2 jdk8u66-b36 +9a158a0c243beb610dbaabd63d6218d3ce5825f1 jdk8u71-b00 +67df26e363fb7e722032fd286673642fc999957c jdk8u71-b01 +1a799d49de23d84f658ade1d3805a1924e7e1e84 jdk8u71-b02 +e06f49d82ef8128b3637937d383b6f0862650deb jdk8u71-b03 +7466029bf3cd3d5eea3055c4f790728263be4a2e jdk8u71-b04 +8a402d51763c083151d0cb434647bd6e1ba4353f jdk8u71-b05 +7dd34cca3538c9bef74a8a1976e14ca51e9857f9 jdk8u71-b06 +bf9d01d1dc6c58b52cb2d0fb07820c51b62c3827 jdk8u71-b07 +19d7052b56715803f40e39aaff00d34ca71f5bc3 jdk8u71-b08 +4fb1acaab7a3205277fa21b083694f1bbb9ae957 jdk8u71-b09 +db019338ef0b6c0ed98c4804c11e07fbee4c6b4c jdk8u71-b10 +9905af25dff7d5bbc73356f5bd14aa10f691a050 jdk8u71-b11 +8aeeda200ace7038e5420b3f27bdd2949abf1029 jdk8u71-b12 +9ba75ccbb03a597abf8d1d2ff5d1d12621725d48 jdk8u71-b13 +12a617fd56938aed03ed5fe48d91f2eafc305825 jdk8u71-b14 +21d9c51cf7df883e67caeccf5fabd0505874f5b6 jdk8u71-b15 +b8f426369187c32551f0a3d571d933908988c81c jdk8u72-b00 +c0205eddb31766ece562483595ec28a7506971e9 jdk8u72-b01 +15ef554f2f2e0a8d7c330191432fcd2126d19dab jdk8u72-b02 +bb98a4ba1556d0505461de98aa3dddf75278c09b jdk8u72-b03 +6c8ceb05ccf78f2f8f72f0870e3f6f3bd4895bb1 jdk8u72-b04 +a2969911663ab29c71a61aa3403e53243ad89923 jdk8u72-b05 +acf0d80cb84f14d787c34360abf2bc38b186999a jdk8u72-b06 +a382a72730f480078af5454afe782de9b6c210d3 jdk8u72-b07 +f26ad2273cd42cde957084ee953a9dc1a2598b5d jdk8u72-b08 +defd2b9a94584d372dea05272ad4f1d6a662c5d1 jdk8u72-b09 +78b0df74e3743be0b578c63e209a03685136d1fa jdk8u72-b10 +37a99b0f443e45fbd0b0a3ed844e6c97d661b754 jdk8u72-b11 +b8e7dd0e21173ad829b40361763d27cb6ac532e9 jdk8u72-b12 +a8e4754b89aecc388623394a20f6d43d4c58f083 jdk8u72-b13 +dc2fdd4e0b8105268b8231040f761f27ab4523f2 jdk8u72-b14 +d6670c5d49ba381405ec9f69a78ccc5b8b0c8473 jdk8u72-b15 +26b99cd20661a1fa05939d1856a9389311e01c4f jdk8u73-b00 +931c31db01ae873525a1b2c306b01129eb431960 jdk8u73-b01 +67566d815a66d958c1f817d65f1621ba1d2e5f33 jdk8u73-b02 +451dda77f6c29bd3260e87f847a9eadae122a759 jdk8u74-b00 +c1031a924f2c910fad078838b88a2f0146f2de98 jdk8u74-b01 +ca9cae9aa9e989bbe6713c91d55c913edeaecce4 jdk8u74-b02 +da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31 +c0242ea4bde19d72be5149feda112a39e8c89b0a jdk8u75-b00 +ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01 +9aef5b5e0a68f20059cfa9e2806b4ff0e11a3d31 jdk8u75-b02 +2df9fe896819362b9075a670b78106b249e50d6d jdk8u75-b03 +32b682649973231b54740c09b10889660f6ebde5 jdk8u75-b04 +1f43bd4fab06d2ca5d1964611df14d8506d6b36e jdk8u75-b05 +916712f178c39d0acbc590f38802133fc86a7346 jdk8u75-b06 +8c791dd1c24d85ebd18b03d49185c2a25263c129 jdk8u75-b07 +e4a935cb6f7178912fd653e2a9514eadec7935ab jdk8u75-b08 +e97c45c377eb8d022cfe24b73737fa312107e0a5 jdk8u75-b09 +d44c7e324682a30e064503ef9582d83a41f4173e jdk8u75-b10 +cc78c97abff85062d6844fa253081e26a0a60150 jdk8u75-b12 +1b6d4fd2730e58f17820930f797938dc182117c4 jdk8u77-b00 +ddd297e340b1170d3cec011ee64e729f8b493c86 jdk8u77-b01 +1b4072e4bb3ad54c4e894998486a8b33f0689160 jdk8u77-b02 +223b64a19e94222dd97b92bb40abcfbc0bf6ef1f jdk8u77-b03 +bbbb05e91c629f8d9eef2ba43933767f68a898b0 jdk8u91-b00 +e36b6ade0499eadfd8673fe62ef0a613af2e6d67 jdk8u91-b13 +fa8991ccf6e5b74890a0b5672440b3c09d8d8732 jdk8u91-b14 +d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00 +c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 +218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02 +2a2720daacaa8d9a3ba9435cfaaf9751241d2062 jdk8u76-b03 +16f7b676725aadafb79ea105b22df112e2593a78 jdk8u76-b04 +35bfaf7f9021b5c1e86effbeac075753a82e9a0c jdk8u76-b05 +6449ee3bf707225372709ac830524c00984c601f jdk8u76-b06 +7d1074c74d6000ec8257917ebfcee3fed4249f7d jdk8u76-b07 +392f8722fc513e28f78c5c563d51af7dc8466b29 jdk8u76-b08 +3bf0f5b8a892defd0bf9731b4e15926881fcda74 jdk8u76-b09 +a2b0ee820059a44be558a2d435b7d85ed5a8b63a jdk8u76-b10 +16aa1f621ec67db1a55ebf6527750164ab63088d jdk8u76-b11 +9a87701e22b3cae79fdfd8cdb732051e02a710fa jdk8u76-b12 +481dcde745b6aec035781ed9f6797cfc93719f71 jdk8u92-b00 +f3e1e734e2d29101a9537ddeb71ecad413fcd352 jdk8u92-b13 b124e22eb772806c13d942cc110de38da0108147 graal-0.1 483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2 9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3
--- a/agent/src/os/linux/LinuxDebuggerLocal.c Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Wed Jun 01 00:11:44 2016 +0200 @@ -209,9 +209,12 @@ verifyBitness(env, (char *) &buf); CHECK_EXCEPTION; + char err_buf[200]; struct ps_prochandle* ph; - if ( (ph = Pgrab(jpid)) == NULL) { - THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); + if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) { + char msg[230]; + snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf); + THROW_NEW_DEBUGGER_EXCEPTION(msg); } (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph);
--- a/agent/src/os/linux/libproc.h Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/os/linux/libproc.h Wed Jun 01 00:11:44 2016 +0200 @@ -73,6 +73,7 @@ #if defined(sparc) || defined(sparcv9) || defined(ppc64) +#include <asm/ptrace.h> #define user_regs_struct pt_regs #endif @@ -86,7 +87,7 @@ struct ps_prochandle; // attach to a process -struct ps_prochandle* Pgrab(pid_t pid); +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len); // attach to a core dump struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile);
--- a/agent/src/os/linux/ps_proc.c Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/os/linux/ps_proc.c Wed Jun 01 00:11:44 2016 +0200 @@ -215,9 +215,12 @@ } // attach to a process/thread specified by "pid" -static bool ptrace_attach(pid_t pid) { +static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) { if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { - print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); + char buf[200]; + char* msg = strerror_r(errno, buf, sizeof(buf)); + snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg); + print_debug("%s\n", err_buf); return false; } else { return ptrace_waitpid(pid); @@ -339,16 +342,17 @@ }; // attach to the process. One and only one exposed stuff -struct ps_prochandle* Pgrab(pid_t pid) { +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { struct ps_prochandle* ph = NULL; thread_info* thr = NULL; if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { - print_debug("can't allocate memory for ps_prochandle\n"); + snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); + print_debug("%s\n", err_buf); return NULL; } - if (ptrace_attach(pid) != true) { + if (ptrace_attach(pid, err_buf, err_buf_len) != true) { free(ph); return NULL; } @@ -371,7 +375,7 @@ thr = ph->threads; while (thr) { // don't attach to the main thread again - if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) { + if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) { // even if one attach fails, we get return NULL Prelease(ph); return NULL;
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed Jun 01 00:11:44 2016 +0200 @@ -1446,7 +1446,7 @@ if (type.equals("threads")) { Threads threads = VM.getVM().getThreads(); for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { - Address base = thread.getBaseOfStackPointer(); + Address base = thread.getStackBase(); Address end = thread.getLastJavaSP(); if (end == null) continue; if (end.lessThan(base)) { @@ -1454,11 +1454,13 @@ base = end; end = tmp; } - out.println("Searching " + base + " " + end); + //out.println("Searching " + base + " " + end); while (base != null && base.lessThan(end)) { Address val = base.getAddressAt(0); if (AddressOps.equal(val, value)) { - out.println(base); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + thread.printThreadIDOn(new PrintStream(bos)); + out.println("found on the stack of thread " + bos.toString() + " at " + base); } base = base.addOffsetTo(stride); } @@ -1601,6 +1603,8 @@ thread.printThreadIDOn(new PrintStream(bos)); if (all || bos.toString().equals(name)) { out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); + thread.printInfoOn(out); + out.println(" "); if (!all) return; } } @@ -1618,6 +1622,8 @@ for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { thread.printThreadIDOn(out); out.println(" " + thread.getThreadName()); + thread.printInfoOn(out); + out.println("\n..."); } } }
--- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 @@ -253,29 +253,30 @@ public static final int _fast_sgetfield = 210; public static final int _fast_aputfield = 211; public static final int _fast_bputfield = 212; - public static final int _fast_cputfield = 213; - public static final int _fast_dputfield = 214; - public static final int _fast_fputfield = 215; - public static final int _fast_iputfield = 216; - public static final int _fast_lputfield = 217; - public static final int _fast_sputfield = 218; - public static final int _fast_aload_0 = 219; - public static final int _fast_iaccess_0 = 220; - public static final int _fast_aaccess_0 = 221; - public static final int _fast_faccess_0 = 222; - public static final int _fast_iload = 223; - public static final int _fast_iload2 = 224; - public static final int _fast_icaload = 225; - public static final int _fast_invokevfinal = 226; - public static final int _fast_linearswitch = 227; - public static final int _fast_binaryswitch = 228; - public static final int _fast_aldc = 229; - public static final int _fast_aldc_w = 230; - public static final int _return_register_finalizer = 231; - public static final int _invokehandle = 232; - public static final int _shouldnotreachhere = 233; // For debugging + public static final int _fast_zputfield = 213; + public static final int _fast_cputfield = 214; + public static final int _fast_dputfield = 215; + public static final int _fast_fputfield = 216; + public static final int _fast_iputfield = 217; + public static final int _fast_lputfield = 218; + public static final int _fast_sputfield = 219; + public static final int _fast_aload_0 = 220; + public static final int _fast_iaccess_0 = 221; + public static final int _fast_aaccess_0 = 222; + public static final int _fast_faccess_0 = 223; + public static final int _fast_iload = 224; + public static final int _fast_iload2 = 225; + public static final int _fast_icaload = 226; + public static final int _fast_invokevfinal = 227; + public static final int _fast_linearswitch = 228; + public static final int _fast_binaryswitch = 229; + public static final int _fast_aldc = 230; + public static final int _fast_aldc_w = 231; + public static final int _return_register_finalizer = 232; + public static final int _invokehandle = 233; + public static final int _shouldnotreachhere = 234; // For debugging - public static final int number_of_codes = 234; + public static final int number_of_codes = 235; // Flag bits derived from format strings, can_trap, can_rewrite, etc.: // semantic flags: @@ -776,6 +777,7 @@ def(_fast_aputfield , "fast_aputfield" , "bJJ" , null , BasicType.getTObject() , 0, true , _putfield ); def(_fast_bputfield , "fast_bputfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _putfield ); + def(_fast_zputfield , "fast_zputfield" , "bJJ" , null , BasicType.getTInt() , 0, true , _putfield ); def(_fast_cputfield , "fast_cputfield" , "bJJ" , null , BasicType.getTChar() , 0, true , _putfield ); def(_fast_dputfield , "fast_dputfield" , "bJJ" , null , BasicType.getTDouble() , 0, true , _putfield ); def(_fast_fputfield , "fast_fputfield" , "bJJ" , null , BasicType.getTFloat() , 0, true , _putfield );
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Tue May 31 08:05:44 2016 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Wed Jun 01 00:11:44 2016 +0200 @@ -415,7 +415,7 @@ } else { tty.println("No Java frames present"); } - tty.println("Base of Stack: " + getBaseOfStackPointer()); + tty.println("Base of Stack: " + getStackBase()); tty.println("Last_Java_SP: " + getLastJavaSP()); tty.println("Last_Java_FP: " + getLastJavaFP()); tty.println("Last_Java_PC: " + getLastJavaPC());
--- a/make/defs.make Tue May 31 08:05:44 2016 +0200 +++ b/make/defs.make Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 @@ -290,7 +290,7 @@ # Use uname output for SRCARCH, but deal with platform differences. If ARCH # is not explicitly listed below, it is treated as x86. - SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc64 zero,$(ARCH))) + SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc ARCH/sparc64= sparc @@ -298,6 +298,7 @@ ARCH/amd64 = x86 ARCH/x86_64 = x86 ARCH/ppc64 = ppc + ARCH/ppc = ppc ARCH/zero = zero # BUILDARCH is usually the same as SRCARCH, except for sparcv9
--- a/make/hotspot_version Tue May 31 08:05:44 2016 +0200 +++ b/make/hotspot_version Wed Jun 01 00:11:44 2016 +0200 @@ -31,11 +31,11 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2015 +HOTSPOT_VM_COPYRIGHT=Copyright 2016 HS_MAJOR_VER=25 -HS_MINOR_VER=66 -HS_BUILD_NUMBER=00 +HS_MINOR_VER=71 +HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 JDK_MINOR_VER=8
--- a/make/linux/Makefile Tue May 31 08:05:44 2016 +0200 +++ b/make/linux/Makefile Wed Jun 01 00:11:44 2016 +0200 @@ -67,8 +67,12 @@ endif endif # C1 is not ported on ppc64, so we cannot build a tiered VM: -ifeq ($(ARCH),ppc64) - FORCE_TIERED=0 +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + FORCE_TIERED=0 + endif endif ifdef LP64
--- a/make/linux/makefiles/defs.make Tue May 31 08:05:44 2016 +0200 +++ b/make/linux/makefiles/defs.make Wed Jun 01 00:11:44 2016 +0200 @@ -69,7 +69,7 @@ endif # sparc -ifeq ($(ARCH), sparc64) +ifneq (,$(findstring $(ARCH), sparc)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 @@ -83,39 +83,35 @@ HS_ARCH = sparc endif -# amd64/x86_64 -ifneq (,$(findstring $(ARCH), amd64 x86_64)) +# i686/i586 and amd64/x86_64 +ifneq (,$(findstring $(ARCH), amd64 x86_64 i686 i586)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 PLATFORM = linux-amd64 VM_PLATFORM = linux_amd64 - HS_ARCH = x86 else ARCH_DATA_MODEL = 32 PLATFORM = linux-i586 VM_PLATFORM = linux_i486 - HS_ARCH = x86 - # We have to reset ARCH to i686 since SRCARCH relies on it - ARCH = i686 endif + HS_ARCH = x86 endif -# i686/i586 ie 32-bit x86 -ifneq (,$(findstring $(ARCH), i686 i586)) - ARCH_DATA_MODEL = 32 - PLATFORM = linux-i586 - VM_PLATFORM = linux_i486 - HS_ARCH = x86 -endif - -# PPC64 -ifeq ($(ARCH), ppc64) - ARCH_DATA_MODEL = 64 - MAKE_ARGS += LP64=1 - PLATFORM = linux-ppc64 - VM_PLATFORM = linux_ppc64 - HS_ARCH = ppc +# PPC +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + MAKE_ARGS += LP64=1 + PLATFORM = linux-ppc64 + VM_PLATFORM = linux_ppc64 + else + ARCH_DATA_MODEL = 32 + PLATFORM = linux-ppc + VM_PLATFORM = linux_ppc + endif + HS_ARCH = ppc endif # On 32 bit linux we build server and client, on 64 bit just server.
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -174,6 +174,7 @@ case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); @@ -302,6 +303,7 @@ switch (state) { case atos: push_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: push_i(); break; @@ -317,6 +319,7 @@ switch (state) { case atos: pop_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: pop_i(); break; @@ -751,6 +754,43 @@ stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP } +void InterpreterMacroAssembler::narrow(Register result) { + Register ret_type = R11_scratch1; + ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method); + lbz(ret_type, in_bytes(ConstMethod::result_type_offset()), R11_scratch1); + + Label notBool, notByte, notChar, done; + + // common case first + cmpwi(CCR0, ret_type, T_INT); + beq(CCR0, done); + + cmpwi(CCR0, ret_type, T_BOOLEAN); + bne(CCR0, notBool); + andi(result, result, 0x1); + b(done); + + bind(notBool); + cmpwi(CCR0, ret_type, T_BYTE); + bne(CCR0, notByte); + extsb(result, result); + b(done); + + bind(notByte); + cmpwi(CCR0, ret_type, T_CHAR); + bne(CCR0, notChar); + andi(result, result, 0xffff); + b(done); + + bind(notChar); + // cmpwi(CCR0, ret_type, T_SHORT); // all that's left + // bne(CCR0, done); + extsh(result, result); + + // Nothing to do for T_INT + bind(done); +} + // Remove activation. // // Unlock the receiver if this is a synchronized method.
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -149,6 +149,8 @@ void get_cpool_and_tags(Register Rcpool, Register Rtags); void is_a(Label& L); + void narrow(Register result); + // Java Call Helpers void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2);
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -296,8 +296,16 @@ __ bind(do_float); __ lfs(floatSlot, 0, arg_java); #if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) + __ stfs(floatSlot, 0, arg_c); +#else __ stfs(floatSlot, 4, arg_c); +#endif #elif defined(AIX) + // Although AIX runs on big endian CPU, float is in most significant + // word of an argument slot. __ stfs(floatSlot, 0, arg_c); #else #error "unknown OS" @@ -632,6 +640,16 @@ __ blr(); } + if (branch_table[ztos] == 0) { // generate only once + __ align(32, 28, 28); // align load + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) + branch_table[ztos] = __ pc(); // non-volatile_entry point + __ lbzx(R3_RET, Rclass_or_obj, Roffset); + __ extsb(R3_RET, R3_RET); + __ beq(CCR6, Lacquire); + __ blr(); + } + if (branch_table[ctos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -592,13 +592,6 @@ "can't identify emitted call"); } else { // variant 1: -#if defined(ABI_ELFv2) - nop(); - calculate_address_from_global_toc(R12, dest, true, true, false); - mtctr(R12); - nop(); - nop(); -#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -608,7 +601,6 @@ mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); -#endif // do the call/jump if (link) {
--- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -766,6 +766,21 @@ // in farg_reg[j] if argument i is the j-th float argument of this call. // case T_FLOAT: +#if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#define FLOAT_WORD_OFFSET_IN_SLOT 1 +#endif +#elif defined(AIX) + // Although AIX runs on big endian CPU, float is in the most + // significant word of an argument slot. +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#error "unknown OS" +#endif if (freg < Argument::n_float_register_parameters_c) { // Put float in register ... reg = farg_reg[freg]; @@ -779,14 +794,14 @@ if (arg >= Argument::n_regs_not_on_stack_c) { // ... and on the stack. guarantee(regs2 != NULL, "must pass float in register and stack slot"); - VMReg reg2 = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + VMReg reg2 = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); regs2[i].set1(reg2); stk += inc_stk_for_intfloat; } } else { // Put float on stack. - reg = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + reg = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); stk += inc_stk_for_intfloat; } regs[i].set1(reg);
--- a/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -154,6 +154,7 @@ switch (state) { case ltos: case btos: + case ztos: case ctos: case stos: case atos: @@ -200,6 +201,7 @@ switch (state) { case ltos: case btos: + case ztos: case ctos: case stos: case atos: @@ -1642,12 +1644,14 @@ // Copied from TemplateTable::_return. // Restoration of lr done by remove_activation. switch (state) { + // Narrow result if state is itos but result type is smaller. + case itos: __ narrow(R17_tos); /* fall through */ case ltos: case btos: + case ztos: case ctos: case stos: - case atos: - case itos: __ mr(R3_RET, R17_tos); break; + case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break; case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need @@ -1717,6 +1721,10 @@ bname = "trace_code_btos {"; tsize = 2; break; + case ztos: + bname = "trace_code_ztos {"; + tsize = 2; + break; case ctos: bname = "trace_code_ctos {"; tsize = 2;
--- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -173,6 +173,7 @@ switch (new_bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: @@ -969,9 +970,21 @@ Rarray = R12_scratch2, Rscratch = R3_ARG1; __ pop_i(Rindex); + __ pop_ptr(Rarray); // tos: val - // Rarray: array ptr (popped by index_check) - __ index_check(Rarray, Rindex, 0, Rscratch, Rarray); + + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(Rscratch, Rarray); + __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch); + int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit()); + __ testbitdi(CCR0, R0, Rscratch, diffbit); + Label L_skip; + __ bfalse(CCR0, L_skip); + __ andi(R17_tos, R17_tos, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); + + __ index_check_without_pop(Rarray, Rindex, 0, Rscratch, Rarray); __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray); } @@ -2100,12 +2113,16 @@ __ remove_activation(state, /* throw_monitor_exception */ true); // Restoration of lr done by remove_activation. switch (state) { + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + case itos: __ narrow(R17_tos); /* fall through */ case ltos: case btos: + case ztos: case ctos: case stos: - case atos: - case itos: __ mr(R3_RET, R17_tos); break; + case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break; case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need @@ -2501,6 +2518,21 @@ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); __ align(32, 28, 28); // Align load. + // __ bind(Lztos); (same code as btos) + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ztos] == 0, "can't compute twice"); + branch_table[ztos] = __ pc(); // non-volatile_entry point + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ push(ztos); + if (!is_static) { + // use btos rewriting, no truncating to t/f bit is needed for getfield. + patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + } + __ beq(CCR6, Lacquire); // Volatile? + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align load. // __ bind(Lctos); __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). assert(branch_table[ctos] == 0, "can't compute twice"); @@ -2590,6 +2622,7 @@ case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break; case Bytecodes::_fast_iputfield: // Fall through case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_zputfield: // Fall through case Bytecodes::_fast_cputfield: // Fall through case Bytecodes::_fast_sputfield: __ push_i(); offs+= Interpreter::stackElementSize; break; case Bytecodes::_fast_lputfield: __ push_l(); offs+=2*Interpreter::stackElementSize; break; @@ -2630,6 +2663,7 @@ case Bytecodes::_fast_aputfield: __ pop_ptr(); break; case Bytecodes::_fast_iputfield: // Fall through case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_zputfield: // Fall through case Bytecodes::_fast_cputfield: // Fall through case Bytecodes::_fast_sputfield: __ pop_i(); break; case Bytecodes::_fast_lputfield: __ pop_l(); break; @@ -2781,6 +2815,21 @@ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); __ align(32, 28, 28); // Align pop. + // __ bind(Lztos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ztos] == 0, "can't compute twice"); + branch_table[ztos] = __ pc(); // non-volatile_entry point + __ pop(ztos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ andi(R17_tos, R17_tos, 0x1); + __ stbx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_zputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ beq(CR_is_vol, Lvolatile); // Volatile? + } + __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); + + __ align(32, 28, 28); // Align pop. // __ bind(Lctos); __ release(); // Volatile entry point (one instruction before non-volatile_entry point). assert(branch_table[ctos] == 0, "can't compute twice"); @@ -2895,6 +2944,9 @@ __ stdx(R17_tos, Rclass_or_obj, Roffset); break; + case Bytecodes::_fast_zputfield: + __ andi(R17_tos, R17_tos, 0x1); // boolean is true if LSB is 1 + // fall through to bputfield case Bytecodes::_fast_bputfield: __ stbx(R17_tos, Rclass_or_obj, Roffset); break;
--- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 @@ -343,7 +343,7 @@ length.set_instruction(x->length()); length.load_item(); } - if (needs_store_check) { + if (needs_store_check || x->check_boolean()) { value.load_item(); } else { value.load_for_store(x->elt_type()); @@ -388,7 +388,8 @@ pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, true /* do_load */, false /* patch */, NULL); } - __ move(value.result(), array_addr, null_check_info); + LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); + __ move(result, array_addr, null_check_info); if (obj_store) { // Precise card mark post_barrier(LIR_OprFact::address(array_addr), value.result());
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -539,6 +539,9 @@ __ cmp(G1_scratch, btos); __ br(Assembler::equal, true, Assembler::pt, xreturn_path); __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); + __ cmp(G1_scratch, ztos); + __ br(Assembler::equal, true, Assembler::pt, xreturn_path); + __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); __ should_not_reach_here(); #endif __ ldsb(Otos_i, G3_scratch, Otos_i);
--- a/src/cpu/sparc/vm/frame_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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 @@ -447,32 +447,6 @@ } #endif // CC_INTERP - -#ifdef ASSERT -// Debugging aid -static frame nth_sender(int n) { - frame f = JavaThread::current()->last_frame(); - - for(int i = 0; i < n; ++i) - f = f.sender((RegisterMap*)NULL); - - printf("first frame %d\n", f.is_first_frame() ? 1 : 0); - printf("interpreted frame %d\n", f.is_interpreted_frame() ? 1 : 0); - printf("java frame %d\n", f.is_java_frame() ? 1 : 0); - printf("entry frame %d\n", f.is_entry_frame() ? 1 : 0); - printf("native frame %d\n", f.is_native_frame() ? 1 : 0); - if (f.is_compiled_frame()) { - if (f.is_deoptimized_frame()) - printf("deoptimized frame 1\n"); - else - printf("compiled frame 1\n"); - } - - return f; -} -#endif - - frame frame::sender_for_entry_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); // Java frame called from C; skip all C frames and return top C
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -211,6 +211,7 @@ case atos: ld_ptr(oop_addr, Otos_l); st_ptr(G0, oop_addr); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: ld(val_addr, Otos_l1); break; @@ -459,9 +460,10 @@ interp_verify_oop(Otos_i, state, __FILE__, __LINE__); switch (state) { case atos: push_ptr(); break; - case btos: push_i(); break; - case ctos: - case stos: push_i(); break; + case btos: // fall through + case ztos: // fall through + case ctos: // fall through + case stos: // fall through case itos: push_i(); break; case ltos: push_l(); break; case ftos: push_f(); break; @@ -475,9 +477,10 @@ void InterpreterMacroAssembler::pop(TosState state) { switch (state) { case atos: pop_ptr(); break; - case btos: pop_i(); break; - case ctos: - case stos: pop_i(); break; + case btos: // fall through + case ztos: // fall through + case ctos: // fall through + case stos: // fall through case itos: pop_i(); break; case ltos: pop_l(); break; case ftos: pop_f(); break; @@ -1111,6 +1114,49 @@ interp_verify_oop(Otos_i, state, __FILE__, __LINE__); } +void InterpreterMacroAssembler::narrow(Register result) { + + ld_ptr(Address(Lmethod, Method::const_offset()), G3_scratch); + ldub(G3_scratch, in_bytes(ConstMethod::result_type_offset()), G3_scratch); + + Label notBool, notByte, notChar, done; + + // common case first + cmp(G3_scratch, T_INT); + br(Assembler::equal, true, pn, done); + delayed()->nop(); + + cmp(G3_scratch, T_BOOLEAN); + br(Assembler::notEqual, true, pn, notBool); + delayed()->cmp(G3_scratch, T_BYTE); + and3(result, 1, result); + ba(done); + delayed()->nop(); + + bind(notBool); + // cmp(G3_scratch, T_BYTE); + br(Assembler::notEqual, true, pn, notByte); + delayed()->cmp(G3_scratch, T_CHAR); + sll(result, 24, result); + sra(result, 24, result); + ba(done); + delayed()->nop(); + + bind(notByte); + // cmp(G3_scratch, T_CHAR); + sll(result, 16, result); + br(Assembler::notEqual, true, pn, done); + delayed()->sra(result, 16, result); + // sll(result, 16, result); + srl(result, 16, result); + + // bind(notChar); + // must be short, instructions already executed in delay slot + // sll(result, 16, result); + // sra(result, 16, result); + + bind(done); +} // remove activation // @@ -1146,6 +1192,7 @@ case ltos: mov(Otos_l2, Otos_l2->after_save()); // fall through // O1 -> I1 #endif case btos: // fall through + case ztos: // fall through case ctos: case stos: // fall through case atos: // fall through
--- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -107,6 +107,8 @@ void dispatch_via (TosState state, address* table); + void narrow(Register result); + // Removes the current activation (incl. unlocking of monitors). // Additionally this code is used for earlyReturn in which case we // want to skip throwing an exception and installing an exception.
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1349,9 +1349,12 @@ } } else if (dst.first()->is_stack()) { // reg to stack - __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), L5); + __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), dst.first()->as_Register()); } }
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -725,6 +725,9 @@ __ cmp(G1_scratch, btos); __ br(Assembler::equal, true, Assembler::pt, xreturn_path); __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); + __ cmp(G1_scratch, ztos); + __ br(Assembler::equal, true, Assembler::pt, xreturn_path); + __ delayed()->ldsb(Otos_i, G3_scratch, Otos_i); __ should_not_reach_here(); #endif __ ldsb(Otos_i, G3_scratch, Otos_i);
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -167,6 +167,7 @@ switch (bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: @@ -913,8 +914,20 @@ transition(itos, vtos); __ pop_i(O2); // index // Otos_i: val + // O2: index // O3: array __ index_check(O3, O2, 0, G3_scratch, O2); + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(O3, G4_scratch); + __ ld(G4_scratch, in_bytes(Klass::layout_helper_offset()), G4_scratch); + __ set(Klass::layout_helper_boolean_diffbit(), G3_scratch); + __ andcc(G3_scratch, G4_scratch, G0); + Label L_skip; + __ br(Assembler::zero, false, Assembler::pn, L_skip); + __ delayed()->nop(); + __ and3(Otos_i, 1, Otos_i); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); __ stb(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_BYTE)); } @@ -1997,6 +2010,12 @@ __ bind(skip_register_finalizer); } + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + if (state == itos) { + __ narrow(Otos_i); + } __ remove_activation(state, /* throw_monitor_exception */ true); // The caller's SP was adjusted upon method entry to accomodate @@ -2216,7 +2235,7 @@ Label checkVolatile; // compute field type - Label notByte, notInt, notShort, notChar, notLong, notFloat, notObj; + Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj; __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags); // Make sure we don't need to mask Rflags after the above shift ConstantPoolCacheEntry::verify_tos_state_shift(); @@ -2271,7 +2290,7 @@ // cmp(Rflags, btos); __ br(Assembler::notEqual, false, Assembler::pt, notByte); - __ delayed() ->cmp(Rflags, ctos); + __ delayed() ->cmp(Rflags, ztos); // btos __ ldsb(Rclass, Roffset, Otos_i); @@ -2284,6 +2303,22 @@ __ bind(notByte); + // cmp(Rflags, ztos); + __ br(Assembler::notEqual, false, Assembler::pt, notBool); + __ delayed() ->cmp(Rflags, ctos); + + // ztos + __ ldsb(Rclass, Roffset, Otos_i); + __ push(itos); + if (!is_static) { + // use btos rewriting, no truncating to t/f bit is needed for getfield. + patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch); + } + __ ba(checkVolatile); + __ delayed()->tst(Lscratch); + + __ bind(notBool); + // cmp(Rflags, ctos); __ br(Assembler::notEqual, false, Assembler::pt, notChar); __ delayed() ->cmp(Rflags, stos); @@ -2445,6 +2480,7 @@ switch (bytecode()) { // save tos values before call_VM() clobbers them case Bytecodes::_fast_aputfield: __ push_ptr(Otos_i); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ push_i(Otos_i); break; @@ -2462,6 +2498,7 @@ switch (bytecode()) { // restore tos values case Bytecodes::_fast_aputfield: __ pop_ptr(Otos_i); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ pop_i(Otos_i); break; @@ -2577,7 +2614,7 @@ ConstantPoolCacheEntry::verify_tos_state_shift(); // compute field type - Label notInt, notShort, notChar, notObj, notByte, notLong, notFloat; + Label notInt, notShort, notChar, notObj, notByte, notBool, notLong, notFloat; if (is_static) { // putstatic with object type most likely, check that first @@ -2645,7 +2682,7 @@ // cmp(Rflags, btos); __ br(Assembler::notEqual, false, Assembler::pt, notByte); - __ delayed()->cmp(Rflags, ltos); + __ delayed()->cmp(Rflags, ztos); // btos { @@ -2660,6 +2697,25 @@ } __ bind(notByte); + + // cmp(Rflags, btos); + __ br(Assembler::notEqual, false, Assembler::pt, notBool); + __ delayed()->cmp(Rflags, ltos); + + // ztos + { + __ pop_i(); + if (!is_static) pop_and_check_object(Rclass); + __ and3(Otos_i, 1, Otos_i); + __ stb(Otos_i, Rclass, Roffset); + if (!is_static) { + patch_bytecode(Bytecodes::_fast_zputfield, G3_scratch, G4_scratch, true, byte_no); + } + __ ba(checkVolatile); + __ delayed()->tst(Lscratch); + } + + __ bind(notBool); // cmp(Rflags, ltos); __ br(Assembler::notEqual, false, Assembler::pt, notLong); __ delayed()->cmp(Rflags, ctos); @@ -2783,6 +2839,7 @@ pop_and_check_object(Rclass); switch (bytecode()) { + case Bytecodes::_fast_zputfield: __ and3(Otos_i, 1, Otos_i); // fall through to bputfield case Bytecodes::_fast_bputfield: __ stb(Otos_i, Rclass, Roffset); break; case Bytecodes::_fast_cputfield: /* fall through */ case Bytecodes::_fast_sputfield: __ sth(Otos_i, Rclass, Roffset); break;
--- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 @@ -283,7 +283,7 @@ length.load_item(); } - if (needs_store_check) { + if (needs_store_check || x->check_boolean()) { value.load_item(); } else { value.load_for_store(x->elt_type()); @@ -331,7 +331,8 @@ // Seems to be a precise post_barrier(LIR_OprFact::address(array_addr), value.result()); } else { - __ move(value.result(), array_addr, null_check_info); + LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); + __ move(result, array_addr, null_check_info); } }
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -870,7 +870,7 @@ rdx, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); - Label notByte, notShort, notChar; + Label notByte, notBool, notShort, notChar; const Address field_address (rax, rcx, Address::times_1); // Need to differentiate between igetfield, agetfield, bgetfield etc. @@ -889,6 +889,11 @@ __ bind(notObj); #endif // _LP64 + __ cmpl(rdx, ztos); + __ jcc(Assembler::notEqual, notBool); + __ load_signed_byte(rax, field_address); + __ jmp(xreturn_path); + __ cmpl(rdx, btos); __ jcc(Assembler::notEqual, notByte); __ load_signed_byte(rax, field_address);
--- a/src/cpu/x86/vm/interp_masm_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -27,6 +27,54 @@ #include "interpreter/interpreter.hpp" #include "oops/methodData.hpp" + +// 8u does not have InterpreterMacroAssembler::load_earlyret_value here + +void InterpreterMacroAssembler::narrow(Register result) { + + // Get method->_constMethod->_result_type + movptr(rcx, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); + movptr(rcx, Address(rcx, Method::const_offset())); + load_unsigned_byte(rcx, Address(rcx, ConstMethod::result_type_offset())); + + Label done, notBool, notByte, notChar; + + // common case first + cmpl(rcx, T_INT); + jcc(Assembler::equal, done); + + // mask integer result to narrower return type. + cmpl(rcx, T_BOOLEAN); + jcc(Assembler::notEqual, notBool); + andl(result, 0x1); + jmp(done); + + bind(notBool); + cmpl(rcx, T_BYTE); + jcc(Assembler::notEqual, notByte); + LP64_ONLY(movsbl(result, result);) + NOT_LP64(shll(result, 24);) // truncate upper 24 bits + NOT_LP64(sarl(result, 24);) // and sign-extend byte + jmp(done); + + bind(notByte); + cmpl(rcx, T_CHAR); + jcc(Assembler::notEqual, notChar); + LP64_ONLY(movzwl(result, result);) + NOT_LP64(andl(result, 0xFFFF);) // truncate upper 16 bits + jmp(done); + + bind(notChar); + // cmpl(rcx, T_SHORT); // all that's left + // jcc(Assembler::notEqual, done); + LP64_ONLY(movswl(result, result);) + NOT_LP64(shll(result, 16);) // truncate upper 16 bits + NOT_LP64(sarl(result, 16);) // and sign-extend short + + // Nothing to do for T_INT + bind(done); +} + #ifndef CC_INTERP void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { Label update, next, none;
--- a/src/cpu/x86/vm/interp_masm_x86.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. 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 @@ -48,6 +48,9 @@ Register _bcp_register; // register that contains the bcp public: + // narrow int return value + void narrow(Register result); + #ifndef CC_INTERP void profile_obj_type(Register obj, const Address& mdo_addr); void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -151,6 +151,7 @@ case ltos: movl(rdx, val_addr1); // fall through case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: movl(rax, val_addr); break; @@ -362,6 +363,7 @@ switch (state) { case atos: pop_ptr(rax); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: pop_i(rax); break; @@ -405,6 +407,7 @@ switch (state) { case atos: push_ptr(rax); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: push_i(rax); break;
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -149,6 +149,7 @@ verify_oop(rax, state); break; case ltos: movptr(rax, val_addr); break; case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: movl(rax, val_addr); break; @@ -387,6 +388,7 @@ switch (state) { case atos: pop_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: pop_i(); break; @@ -404,6 +406,7 @@ switch (state) { case atos: push_ptr(); break; case btos: + case ztos: case ctos: case stos: case itos: push_i(); break;
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -6143,7 +6143,9 @@ // Save caller's stack pointer into RBP if the frame pointer is preserved. if (PreserveFramePointer) { movptr(rbp, rsp); - addptr(rbp, framesize + wordSize); + if (framesize > 0) { + addptr(rbp, framesize); + } } }
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -713,7 +713,7 @@ rdx, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); - Label notByte, notShort, notChar; + Label notByte, notBool, notShort, notChar; const Address field_address (rax, rcx, Address::times_1); // Need to differentiate between igetfield, agetfield, bgetfield etc. @@ -728,6 +728,12 @@ __ jmp(xreturn_path); __ bind(notByte); + __ cmpl(rdx, ztos); + __ jcc(Assembler::notEqual, notBool); + __ load_signed_byte(rax, field_address); + __ jmp(xreturn_path); + + __ bind(notBool); __ cmpl(rdx, stos); __ jcc(Assembler::notEqual, notShort); __ load_signed_short(rax, field_address);
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -695,7 +695,7 @@ ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); - Label notObj, notInt, notByte, notShort; + Label notObj, notInt, notByte, notBool, notShort; const Address field_address(rax, rcx, Address::times_1); // Need to differentiate between igetfield, agetfield, bgetfield etc. @@ -726,6 +726,13 @@ __ jmp(xreturn_path); __ bind(notByte); + __ cmpl(rdx, ztos); + __ jcc(Assembler::notEqual, notBool); + // ztos + __ load_signed_byte(rax, field_address); + __ jmp(xreturn_path); + + __ bind(notBool); __ cmpl(rdx, stos); __ jcc(Assembler::notEqual, notShort); // stos
--- a/src/cpu/x86/vm/templateTable_x86_32.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -212,6 +212,7 @@ switch (bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: @@ -988,11 +989,21 @@ void TemplateTable::bastore() { transition(itos, vtos); __ pop_i(rbx); - // rax,: value + // rax: value + // rbx: index // rdx: array - index_check(rdx, rbx); // prefer index in rbx, - // rbx,: index - __ movb(Address(rdx, rbx, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), rax); + index_check(rdx, rbx); // prefer index in rbx + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(rcx, rdx); + __ movl(rcx, Address(rcx, Klass::layout_helper_offset())); + int diffbit = Klass::layout_helper_boolean_diffbit(); + __ testl(rcx, diffbit); + Label L_skip; + __ jccb(Assembler::zero, L_skip); + __ andl(rax, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); + __ movb(Address(rdx, rbx, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), rax); } @@ -2037,7 +2048,14 @@ __ bind(skip_register_finalizer); } + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + if (state == itos) { + __ narrow(rax); + } __ remove_activation(state, rsi); + __ jmp(rsi); } @@ -2234,7 +2252,7 @@ const Address lo(obj, off, Address::times_1, 0*wordSize); const Address hi(obj, off, Address::times_1, 1*wordSize); - Label Done, notByte, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; + Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); assert(btos == 0, "change code, btos != 0"); @@ -2251,6 +2269,22 @@ __ jmp(Done); __ bind(notByte); + + __ cmpl(flags, ztos); + __ jcc(Assembler::notEqual, notBool); + + // ztos (same code as btos) + __ load_signed_byte(rax, lo); + __ push(ztos); + // Rewrite bytecode to be faster + if (!is_static) { + // use btos rewriting, no truncating to t/f bit is needed for getfield. + patch_bytecode(Bytecodes::_fast_bgetfield, rcx, rbx); + } + __ jmp(Done); + + __ bind(notBool); + // itos __ cmpl(flags, itos ); __ jcc(Assembler::notEqual, notInt); @@ -2450,7 +2484,7 @@ const Address lo(obj, off, Address::times_1, 0*wordSize); const Address hi(obj, off, Address::times_1, 1*wordSize); - Label notByte, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; + Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); assert(btos == 0, "change code, btos != 0"); @@ -2469,6 +2503,22 @@ } __ bind(notByte); + __ cmpl(flags, ztos); + __ jcc(Assembler::notEqual, notBool); + + // ztos + { + __ pop(ztos); + if (!is_static) pop_and_check_object(obj); + __ andl(rax, 0x1); + __ movb(lo, rax); + if (!is_static) { + patch_bytecode(Bytecodes::_fast_zputfield, rcx, rbx, true, byte_no); + } + __ jmp(Done); + } + + __ bind(notBool); __ cmpl(flags, itos); __ jcc(Assembler::notEqual, notInt); @@ -2640,6 +2690,7 @@ switch (bytecode()) { // load values into the jvalue object case Bytecodes::_fast_aputfield: __ push_ptr(rax); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ push_i(rax); break; @@ -2662,6 +2713,7 @@ switch (bytecode()) { // restore tos values case Bytecodes::_fast_aputfield: __ pop_ptr(rax); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ pop_i(rax); break; @@ -2712,6 +2764,8 @@ // access field switch (bytecode()) { + case Bytecodes::_fast_zputfield: __ andl(rax, 0x1); // boolean is true if LSB is 1 + // fall through to bputfield case Bytecodes::_fast_bputfield: __ movb(lo, rax); break; case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: __ movw(lo, rax); break; @@ -2746,6 +2800,8 @@ // access field switch (bytecode()) { + case Bytecodes::_fast_zputfield: __ andl(rax, 0x1); // boolean is true if LSB is 1 + // fall through to bputfield case Bytecodes::_fast_bputfield: __ movb(lo, rax); break; case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: __ movw(lo, rax); break;
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -215,6 +215,7 @@ switch (bc) { case Bytecodes::_fast_aputfield: case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_zputfield: case Bytecodes::_fast_cputfield: case Bytecodes::_fast_dputfield: case Bytecodes::_fast_fputfield: @@ -1014,6 +1015,16 @@ // ebx: index // rdx: array index_check(rdx, rbx); // prefer index in ebx + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(rcx, rdx); + __ movl(rcx, Address(rcx, Klass::layout_helper_offset())); + int diffbit = Klass::layout_helper_boolean_diffbit(); + __ testl(rcx, diffbit); + Label L_skip; + __ jccb(Assembler::zero, L_skip); + __ andl(rax, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); __ movb(Address(rdx, rbx, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), @@ -2067,7 +2078,14 @@ __ bind(skip_register_finalizer); } + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + if (state == itos) { + __ narrow(rax); + } __ remove_activation(state, r13); + __ jmp(r13); } @@ -2285,7 +2303,7 @@ const Address field(obj, off, Address::times_1); - Label Done, notByte, notInt, notShort, notChar, + Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); @@ -2304,6 +2322,20 @@ __ jmp(Done); __ bind(notByte); + __ cmpl(flags, ztos); + __ jcc(Assembler::notEqual, notBool); + + // ztos (same code as btos) + __ load_signed_byte(rax, field); + __ push(ztos); + // Rewrite bytecode to be faster + if (!is_static) { + // use btos rewriting, no truncating to t/f bit is needed for getfield. + patch_bytecode(Bytecodes::_fast_bgetfield, bc, rbx); + } + __ jmp(Done); + + __ bind(notBool); __ cmpl(flags, atos); __ jcc(Assembler::notEqual, notObj); // atos @@ -2493,7 +2525,7 @@ // field address const Address field(obj, off, Address::times_1); - Label notByte, notInt, notShort, notChar, + Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift); @@ -2514,6 +2546,22 @@ } __ bind(notByte); + __ cmpl(flags, ztos); + __ jcc(Assembler::notEqual, notBool); + + // ztos + { + __ pop(ztos); + if (!is_static) pop_and_check_object(obj); + __ andl(rax, 0x1); + __ movb(field, rax); + if (!is_static) { + patch_bytecode(Bytecodes::_fast_zputfield, bc, rbx, true, byte_no); + } + __ jmp(Done); + } + + __ bind(notBool); __ cmpl(flags, atos); __ jcc(Assembler::notEqual, notObj); @@ -2662,6 +2710,7 @@ switch (bytecode()) { // load values into the jvalue object case Bytecodes::_fast_aputfield: __ push_ptr(rax); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ push_i(rax); break; @@ -2687,6 +2736,7 @@ switch (bytecode()) { // restore tos values case Bytecodes::_fast_aputfield: __ pop_ptr(rax); break; case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through case Bytecodes::_fast_sputfield: // fall through case Bytecodes::_fast_cputfield: // fall through case Bytecodes::_fast_iputfield: __ pop_i(rax); break; @@ -2742,6 +2792,9 @@ case Bytecodes::_fast_iputfield: __ movl(field, rax); break; + case Bytecodes::_fast_zputfield: + __ andl(rax, 0x1); // boolean is true if LSB is 1 + // fall through to bputfield case Bytecodes::_fast_bputfield: __ movb(field, rax); break;
--- a/src/cpu/x86/vm/vm_version_x86.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -593,7 +593,7 @@ result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu / cores_per_cpu(); } - return result; + return (result == 0 ? 1 : result); } static intx prefetch_data_size() {
--- a/src/cpu/x86/vm/x86_32.ad Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/x86_32.ad Wed Jun 01 00:11:44 2016 +0200 @@ -566,7 +566,11 @@ st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + if (framesize > 0) { + st->print("\n\t"); + st->print("ADD EBP, #%d", framesize); + } } }
--- a/src/cpu/x86/vm/x86_64.ad Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/x86/vm/x86_64.ad Wed Jun 01 00:11:44 2016 +0200 @@ -863,7 +863,11 @@ st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + if (framesize > 0) { + st->print("\n\t"); + st->print("addq rbp, #%d", framesize); + } } }
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,6 +81,30 @@ return 0; } +intptr_t narrow(BasicType type, intptr_t result) { + // mask integer result to narrower return type. + switch (type) { + case T_BOOLEAN: + return result&1; + case T_BYTE: + return (intptr_t)(jbyte)result; + case T_CHAR: + return (intptr_t)(uintptr_t)(jchar)result; + case T_SHORT: + return (intptr_t)(jshort)result; + case T_OBJECT: // nothing to do fall through + case T_ARRAY: + case T_LONG: + case T_INT: + case T_FLOAT: + case T_DOUBLE: + case T_VOID: + return result; + default : ShouldNotReachHere(); + } +} + + void CppInterpreter::main_loop(int recurse, TRAPS) { JavaThread *thread = (JavaThread *) THREAD; ZeroStack *stack = thread->zero_stack(); @@ -160,7 +184,7 @@ } else if (istate->msg() == BytecodeInterpreter::return_from_method) { // Copy the result into the caller's frame - result_slots = type2size[result_type_of(method)]; + result_slots = type2size[method->result_type()]; assert(result_slots >= 0 && result_slots <= 2, "what?"); result = istate->stack() + result_slots; break; @@ -194,8 +218,14 @@ stack->set_sp(stack->sp() + method->max_locals()); // Push our result - for (int i = 0; i < result_slots; i++) - stack->push(result[-i]); + for (int i = 0; i < result_slots; i++) { + // Adjust result to smaller + intptr_t res = result[-i]; + if (result_slots == 1) { + res = narrow(method->result_type(), res); + } + stack->push(res); + } } int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { @@ -406,7 +436,7 @@ // Push our result if (!HAS_PENDING_EXCEPTION) { - BasicType type = result_type_of(method); + BasicType type = method->result_type(); stack->set_sp(stack->sp() - type2size[type]); switch (type) { @@ -528,6 +558,7 @@ break; case btos: + case ztos: SET_LOCALS_INT(object->byte_field_acquire(entry->f2_as_index()), 0); break; @@ -566,6 +597,7 @@ break; case btos: + case ztos: SET_LOCALS_INT(object->byte_field(entry->f2_as_index()), 0); break; @@ -764,26 +796,6 @@ return i; } -BasicType CppInterpreter::result_type_of(Method* method) { - BasicType t; - switch (method->result_index()) { - case 0 : t = T_BOOLEAN; break; - case 1 : t = T_CHAR; break; - case 2 : t = T_BYTE; break; - case 3 : t = T_SHORT; break; - case 4 : t = T_INT; break; - case 5 : t = T_LONG; break; - case 6 : t = T_VOID; break; - case 7 : t = T_FLOAT; break; - case 8 : t = T_DOUBLE; break; - case 9 : t = T_OBJECT; break; - default: ShouldNotReachHere(); - } - assert(AbstractInterpreter::BasicType_as_index(t) == method->result_index(), - "out of step with AbstractInterpreter::BasicType_as_index"); - return t; -} - address InterpreterGenerator::generate_empty_entry() { if (!UseFastEmptyMethods) return NULL;
--- a/src/cpu/zero/vm/cppInterpreter_zero.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/zero/vm/cppInterpreter_zero.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -49,8 +49,4 @@ static intptr_t* calculate_unwind_sp(ZeroStack* stack, oop method_handle); static void throw_exception(JavaThread* thread, Symbol* name,char *msg=NULL); - private: - // Fast result type determination - static BasicType result_type_of(Method* method); - #endif // CPU_ZERO_VM_CPPINTERPRETER_ZERO_HPP
--- a/src/cpu/zero/vm/frame_zero.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/cpu/zero/vm/frame_zero.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -216,7 +216,7 @@ valuebuf[buflen - 1] = '\0'; // Print the result - st->print_cr(" " PTR_FORMAT ": %-21s = %s", addr, fieldbuf, valuebuf); + st->print_cr(" " PTR_FORMAT ": %-21s = %s", p2i(addr), fieldbuf, valuebuf); } }
--- a/src/os/aix/vm/perfMemory_aix.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/aix/vm/perfMemory_aix.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2013 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -201,6 +201,7 @@ // the backing store files. Returns true if the directory is considered // a secure location. Returns false if the statbuf is a symbolic link or // if an error occurred. +// static bool is_statbuf_secure(struct stat *statp) { if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { // The path represents a link or some non-directory file type, @@ -209,15 +210,18 @@ return false; } // We have an existing directory, check if the permissions are safe. + // if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { // The directory is open for writing and could be subjected // to a symlink or a hard link attack. Declare it insecure. + // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. + // return false; } return true; @@ -228,6 +232,7 @@ // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. +// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -454,13 +459,27 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory. +// static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { int result;
--- a/src/os/bsd/dtrace/hotspot.d Tue May 31 08:05:44 2016 +0200 +++ b/src/os/bsd/dtrace/hotspot.d Wed Jun 01 00:11:44 2016 +0200 @@ -47,8 +47,8 @@ probe mem__pool__gc__end( char*, uintptr_t, char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); - probe thread__probe__start(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); - probe thread__probe__stop(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + probe thread__start(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + probe thread__stop(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); probe thread__sleep__begin(long long); probe thread__sleep__end(int); probe thread__yield(); @@ -68,7 +68,7 @@ probe monitor__contended__entered(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__contended__exit(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__wait(uintptr_t, uintptr_t, char*, uintptr_t, uintptr_t); - probe monitor__probe__waited(uintptr_t, uintptr_t, char*, uintptr_t); + probe monitor__waited(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__notify(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__notifyAll(uintptr_t, uintptr_t, char*, uintptr_t);
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. 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 @@ -217,9 +217,9 @@ // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. // return false; @@ -375,10 +375,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/linux/vm/os_linux.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/linux/vm/os_linux.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -5922,9 +5922,11 @@ status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant"); } else { + // must capture correct index before unlocking + int index = _cur_index; status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant"); - status = pthread_cond_signal (&_cond[_cur_index]); + status = pthread_cond_signal (&_cond[index]); assert (status == 0, "invariant"); } } else {
--- a/src/os/linux/vm/perfMemory_linux.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/linux/vm/perfMemory_linux.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. 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 @@ -217,9 +217,9 @@ // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. // return false; @@ -374,10 +374,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/solaris/vm/os_solaris.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/solaris/vm/os_solaris.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -178,75 +178,6 @@ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); -// Thread Local Storage -// This is common to all Solaris platforms so it is defined here, -// in this common file. -// The declarations are in the os_cpu threadLS*.hpp files. -// -// Static member initialization for TLS -Thread* ThreadLocalStorage::_get_thread_cache[ThreadLocalStorage::_pd_cache_size] = {NULL}; - -#ifndef PRODUCT -#define _PCT(n,d) ((100.0*(double)(n))/(double)(d)) - -int ThreadLocalStorage::_tcacheHit = 0; -int ThreadLocalStorage::_tcacheMiss = 0; - -void ThreadLocalStorage::print_statistics() { - int total = _tcacheMiss+_tcacheHit; - tty->print_cr("Thread cache hits %d misses %d total %d percent %f\n", - _tcacheHit, _tcacheMiss, total, _PCT(_tcacheHit, total)); -} -#undef _PCT -#endif // PRODUCT - -Thread* ThreadLocalStorage::get_thread_via_cache_slowly(uintptr_t raw_id, - int index) { - Thread *thread = get_thread_slow(); - if (thread != NULL) { - address sp = os::current_stack_pointer(); - guarantee(thread->_stack_base == NULL || - (sp <= thread->_stack_base && - sp >= thread->_stack_base - thread->_stack_size) || - is_error_reported(), - "sp must be inside of selected thread stack"); - - thread->set_self_raw_id(raw_id); // mark for quick retrieval - _get_thread_cache[ index ] = thread; - } - return thread; -} - - -static const double all_zero[ sizeof(Thread) / sizeof(double) + 1 ] = {0}; -#define NO_CACHED_THREAD ((Thread*)all_zero) - -void ThreadLocalStorage::pd_set_thread(Thread* thread) { - - // Store the new value before updating the cache to prevent a race - // between get_thread_via_cache_slowly() and this store operation. - os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread); - - // Update thread cache with new thread if setting on thread create, - // or NO_CACHED_THREAD (zeroed) thread if resetting thread on exit. - uintptr_t raw = pd_raw_thread_id(); - int ix = pd_cache_index(raw); - _get_thread_cache[ix] = thread == NULL ? NO_CACHED_THREAD : thread; -} - -void ThreadLocalStorage::pd_init() { - for (int i = 0; i < _pd_cache_size; i++) { - _get_thread_cache[i] = NO_CACHED_THREAD; - } -} - -// Invalidate all the caches (happens to be the same as pd_init). -void ThreadLocalStorage::pd_invalidate_all() { pd_init(); } - -#undef NO_CACHED_THREAD - -// END Thread Local Storage - static inline size_t adjust_stack_size(address base, size_t size) { if ((ssize_t)size < 0) { // 4759953: Compensate for ridiculous stack size. @@ -1473,64 +1404,6 @@ return (int)(_initial_pid ? _initial_pid : getpid()); } -int os::allocate_thread_local_storage() { - // %%% in Win32 this allocates a memory segment pointed to by a - // register. Dan Stein can implement a similar feature in - // Solaris. Alternatively, the VM can do the same thing - // explicitly: malloc some storage and keep the pointer in a - // register (which is part of the thread's context) (or keep it - // in TLS). - // %%% In current versions of Solaris, thr_self and TSD can - // be accessed via short sequences of displaced indirections. - // The value of thr_self is available as %g7(36). - // The value of thr_getspecific(k) is stored in %g7(12)(4)(k*4-4), - // assuming that the current thread already has a value bound to k. - // It may be worth experimenting with such access patterns, - // and later having the parameters formally exported from a Solaris - // interface. I think, however, that it will be faster to - // maintain the invariant that %g2 always contains the - // JavaThread in Java code, and have stubs simply - // treat %g2 as a caller-save register, preserving it in a %lN. - thread_key_t tk; - if (thr_keycreate( &tk, NULL ) ) - fatal(err_msg("os::allocate_thread_local_storage: thr_keycreate failed " - "(%s)", strerror(errno))); - return int(tk); -} - -void os::free_thread_local_storage(int index) { - // %%% don't think we need anything here - // if ( pthread_key_delete((pthread_key_t) tk) ) - // fatal("os::free_thread_local_storage: pthread_key_delete failed"); -} - -#define SMALLINT 32 // libthread allocate for tsd_common is a version specific - // small number - point is NO swap space available -void os::thread_local_storage_at_put(int index, void* value) { - // %%% this is used only in threadLocalStorage.cpp - if (thr_setspecific((thread_key_t)index, value)) { - if (errno == ENOMEM) { - vm_exit_out_of_memory(SMALLINT, OOM_MALLOC_ERROR, - "thr_setspecific: out of swap space"); - } else { - fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed " - "(%s)", strerror(errno))); - } - } else { - ThreadLocalStorage::set_thread_in_slot ((Thread *) value) ; - } -} - -// This function could be called before TLS is initialized, for example, when -// VM receives an async signal or when VM causes a fatal error during -// initialization. Return NULL if thr_getspecific() fails. -void* os::thread_local_storage_at(int index) { - // %%% this is used only in threadLocalStorage.cpp - void* r = NULL; - return thr_getspecific((thread_key_t)index, &r) != 0 ? NULL : r; -} - - // gethrtime() should be monotonic according to the documentation, // but some virtualized platforms are known to break this guarantee. // getTimeNanos() must be guaranteed not to move backwards, so we @@ -2168,7 +2041,9 @@ st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10); st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); st->cr(); - (void) check_addr0(st); + if (VMError::fatal_error_in_progress()) { + (void) check_addr0(st); + } } void os::print_siginfo(outputStream* st, void* siginfo) {
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. 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 @@ -219,9 +219,9 @@ // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. // return false; @@ -377,10 +377,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/solaris/vm/thread_solaris.inline.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os/solaris/vm/thread_solaris.inline.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. 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 @@ -40,19 +40,12 @@ // For SPARC, to avoid excessive register window spill-fill faults, // we aggressively inline these routines. -inline Thread* ThreadLocalStorage::thread() { - // don't use specialized code if +UseMallocOnly -- may confuse Purify et al. - debug_only(if (UseMallocOnly) return get_thread_slow();); +inline void ThreadLocalStorage::set_thread(Thread* thread) { + _thr_current = thread; +} - uintptr_t raw = pd_raw_thread_id(); - int ix = pd_cache_index(raw); - Thread* candidate = ThreadLocalStorage::_get_thread_cache[ix]; - if (candidate != NULL && candidate->self_raw_id() == raw) { - // hit - return candidate; - } else { - return ThreadLocalStorage::get_thread_via_cache_slowly(raw, ix); - } +inline Thread* ThreadLocalStorage::thread() { + return _thr_current; } #endif // OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
--- a/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2015, Oracle and/or its affiliates. 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 @@ -53,6 +53,10 @@ return cpuinfo_field_contains("cpu", "Niagara"); } +static bool detect_M_family() { + return cpuinfo_field_contains("cpu", "SPARC-M"); +} + static bool detect_blkinit() { return cpuinfo_field_contains("cpucaps", "blkinit"); } @@ -66,6 +70,11 @@ features = niagara1_m | T_family_m; } + if (detect_M_family()) { + NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Detected Linux on M family");) + features = sun4v_m | generic_v9_m | M_family_m | T_family_m; + } + if (detect_blkinit()) { features |= blk_init_instructions_m; }
--- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -55,8 +55,8 @@ #include "utilities/vmError.hpp" address os::current_stack_pointer() { - address dummy = (address) &dummy; - return dummy; + // return the address of the current function + return (address)__builtin_frame_address(0); } frame os::get_sender_for_C_frame(frame* fr) {
--- a/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -26,19 +26,26 @@ #include "runtime/thread.inline.hpp" #include "runtime/threadLocalStorage.hpp" -// Provides an entry point we can link against and -// a buffer we can emit code into. The buffer is -// filled by ThreadLocalStorage::generate_code_for_get_thread -// and called from ThreadLocalStorage::thread() +// True thread-local variable +__thread Thread * ThreadLocalStorage::_thr_current = NULL; + +// Implementations needed to support the shared API -#include <sys/systeminfo.h> +void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do -// The portable TLS mechanism (get_thread_via_cache) is enough on SPARC. -// There is no need for hand-assembling a special function. -void ThreadLocalStorage::generate_code_for_get_thread() { +bool ThreadLocalStorage::_initialized = false; + +void ThreadLocalStorage::init() { + _initialized = true; } -void ThreadLocalStorage::set_thread_in_slot (Thread * self) {} +bool ThreadLocalStorage::is_initialized() { + return _initialized; +} + +Thread* ThreadLocalStorage::get_thread_slow() { + return thread(); +} extern "C" Thread* get_thread() { return ThreadLocalStorage::thread();
--- a/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -25,47 +25,15 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP #define OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP -public: - // Java Thread - force inlining - static inline Thread* thread() ; +// Solaris specific implementation involves simple, direct use +// of a compiler-based thread-local variable private: - static Thread* _get_thread_cache[]; // index by [(raw_id>>9)^(raw_id>>20) % _pd_cache_size] - static Thread* get_thread_via_cache_slowly(uintptr_t raw_id, int index); + static __thread Thread * _thr_current; - NOT_PRODUCT(static int _tcacheHit;) - NOT_PRODUCT(static int _tcacheMiss;) + static bool _initialized; // needed for shared API public: - - // Print cache hit/miss statistics - static void print_statistics() PRODUCT_RETURN; - - enum Constants { - _pd_cache_size = 256*2 // projected typical # of threads * 2 - }; - - static void set_thread_in_slot (Thread *) ; - - static uintptr_t pd_raw_thread_id() { - return _raw_thread_id(); - } - - static int pd_cache_index(uintptr_t raw_id) { - // Hash function: From email from Dave: - // The hash function deserves an explanation. %g7 points to libthread's - // "thread" structure. On T1 the thread structure is allocated on the - // user's stack (yes, really!) so the ">>20" handles T1 where the JVM's - // stack size is usually >= 1Mb. The ">>9" is for T2 where Roger allocates - // globs of thread blocks contiguously. The "9" has to do with the - // expected size of the T2 thread structure. If these constants are wrong - // the worst thing that'll happen is that the hit rate for heavily threaded - // apps won't be as good as it could be. If you want to burn another - // shift+xor you could mix together _all of the %g7 bits to form the hash, - // but I think that's excessive. Making the change above changed the - // T$ miss rate on SpecJBB (on a 16X system) from about 3% to imperceptible. - uintptr_t ix = (int) (((raw_id >> 9) ^ (raw_id >> 20)) % _pd_cache_size); - return ix; - } + static inline Thread* thread(); #endif // OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP
--- a/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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 @@ -23,11 +23,10 @@ */ #include "precompiled.hpp" -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "runtime/os.hpp" #include "runtime/threadLocalStorage.hpp" - +#include "runtime/thread.inline.hpp" void MacroAssembler::int3() { push(rax); @@ -39,98 +38,32 @@ pop(rax); } -#define __ _masm-> -#ifndef _LP64 -static void slow_call_thr_specific(MacroAssembler* _masm, Register thread) { - - // slow call to of thr_getspecific - // int thr_getspecific(thread_key_t key, void **value); - // Consider using pthread_getspecific instead. - -__ push(0); // allocate space for return value - if (thread != rax) __ push(rax); // save rax, if caller still wants it -__ push(rcx); // save caller save -__ push(rdx); // save caller save +// This is simply a call to ThreadLocalStorage::thread() +void MacroAssembler::get_thread(Register thread) { if (thread != rax) { -__ lea(thread, Address(rsp, 3 * sizeof(int))); // address of return value - } else { -__ lea(thread, Address(rsp, 2 * sizeof(int))); // address of return value + push(rax); } -__ push(thread); // and pass the address -__ push(ThreadLocalStorage::thread_index()); // the key -__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, thr_getspecific))); -__ increment(rsp, 2 * wordSize); -__ pop(rdx); -__ pop(rcx); - if (thread != rax) __ pop(rax); -__ pop(thread); - -} -#else -static void slow_call_thr_specific(MacroAssembler* _masm, Register thread) { - // slow call to of thr_getspecific - // int thr_getspecific(thread_key_t key, void **value); - // Consider using pthread_getspecific instead. + push(rdi); + push(rsi); + push(rdx); + push(rcx); + push(r8); + push(r9); + push(r10); + push(r11); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadLocalStorage::thread))); + + pop(r11); + pop(r10); + pop(r9); + pop(r8); + pop(rcx); + pop(rdx); + pop(rsi); + pop(rdi); if (thread != rax) { -__ push(rax); - } -__ push(0); // space for return value -__ push(rdi); -__ push(rsi); -__ lea(rsi, Address(rsp, 16)); // pass return value address -__ push(rdx); -__ push(rcx); -__ push(r8); -__ push(r9); -__ push(r10); - // XXX -__ mov(r10, rsp); -__ andptr(rsp, -16); -__ push(r10); -__ push(r11); - -__ movl(rdi, ThreadLocalStorage::thread_index()); -__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, thr_getspecific))); - -__ pop(r11); -__ pop(rsp); -__ pop(r10); -__ pop(r9); -__ pop(r8); -__ pop(rcx); -__ pop(rdx); -__ pop(rsi); -__ pop(rdi); -__ pop(thread); // load return value - if (thread != rax) { -__ pop(rax); + movl(thread, rax); + pop(rax); } } -#endif //LP64 - -void MacroAssembler::get_thread(Register thread) { - - int segment = NOT_LP64(Assembler::GS_segment) LP64_ONLY(Assembler::FS_segment); - // Try to emit a Solaris-specific fast TSD/TLS accessor. - ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_getTlsAccessMode (); - if (tlsMode == ThreadLocalStorage::pd_tlsAccessIndirect) { // T1 - // Use thread as a temporary: mov r, gs:[0]; mov r, [r+tlsOffset] - emit_int8 (segment); - // ExternalAddress doesn't work because it can't take NULL - AddressLiteral null(0, relocInfo::none); - movptr (thread, null); - movptr(thread, Address(thread, ThreadLocalStorage::pd_getTlsOffset())) ; - return ; - } else - if (tlsMode == ThreadLocalStorage::pd_tlsAccessDirect) { // T2 - // mov r, gs:[tlsOffset] - emit_int8 (segment); - AddressLiteral tls_off((address)ThreadLocalStorage::pd_getTlsOffset(), relocInfo::none); - movptr (thread, tls_off); - return ; - } - - slow_call_thr_specific(this, thread); - -}
--- a/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -26,167 +26,27 @@ #include "runtime/thread.inline.hpp" #include "runtime/threadLocalStorage.hpp" -#ifdef AMD64 -extern "C" Thread* fs_load(ptrdiff_t tlsOffset); -extern "C" intptr_t fs_thread(); -#else -// From solaris_i486.s -extern "C" Thread* gs_load(ptrdiff_t tlsOffset); -extern "C" intptr_t gs_thread(); -#endif // AMD64 +// True thread-local variable +__thread Thread * ThreadLocalStorage::_thr_current = NULL; + +// Implementations needed to support the shared API -// tlsMode encoding: -// -// pd_tlsAccessUndefined : uninitialized -// pd_tlsAccessSlow : not available -// pd_tlsAccessIndirect : -// old-style indirect access - present in "T1" libthread. -// use thr_slot_sync_allocate() to attempt to allocate a slot. -// pd_tlsAccessDirect : -// new-style direct access - present in late-model "T2" libthread. -// Allocate the offset (slot) via _thr_slot_offset() or by -// defining an IE- or LE-mode TLS/TSD slot in the launcher and then passing -// that offset into libjvm.so. -// See http://sac.eng/Archives/CaseLog/arc/PSARC/2003/159/. -// -// Note that we have a capability gap - some early model T2 forms -// (e.g., unpatched S9) have neither _thr_slot_sync_allocate() nor -// _thr_slot_offset(). In that case we revert to the usual -// thr_getspecific accessor. -// +void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do -static ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_tlsAccessUndefined ; -static ptrdiff_t tlsOffset = 0 ; -static thread_key_t tlsKey ; - -typedef int (*TSSA_Entry) (ptrdiff_t *, int, int) ; -typedef ptrdiff_t (*TSO_Entry) (int) ; +bool ThreadLocalStorage::_initialized = false; -ThreadLocalStorage::pd_tlsAccessMode ThreadLocalStorage::pd_getTlsAccessMode () -{ - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - return tlsMode ; -} - -ptrdiff_t ThreadLocalStorage::pd_getTlsOffset () { - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - return tlsOffset ; +void ThreadLocalStorage::init() { + _initialized = true; } -// TODO: Consider the following improvements: -// -// 1. Convert from thr_*specific* to pthread_*specific*. -// The pthread_ forms are slightly faster. Also, the -// pthread_ forms have a pthread_key_delete() API which -// would aid in clean JVM shutdown and the eventual goal -// of permitting a JVM to reinstantiate itself withing a process. -// -// 2. See ThreadLocalStorage::init(). We end up allocating -// two TLS keys during VM startup. That's benign, but we could collapse -// down to one key without too much trouble. -// -// 3. MacroAssembler::get_thread() currently emits calls to thr_getspecific(). -// Modify get_thread() to call Thread::current() instead. -// -// 4. Thread::current() currently uses a cache keyed by %gs:[0]. -// (The JVM has PSARC permission to use %g7/%gs:[0] -// as an opaque temporally unique thread identifier). -// For C++ access to a thread's reflexive "self" pointer we -// should consider using one of the following: -// a. a radix tree keyed by %esp - as in EVM. -// This requires two loads (the 2nd dependent on the 1st), but -// is easily inlined and doesn't require a "miss" slow path. -// b. a fast TLS/TSD slot allocated by _thr_slot_offset -// or _thr_slot_sync_allocate. -// -// 5. 'generate_code_for_get_thread' is a misnomer. -// We should change it to something more general like -// pd_ThreadSelf_Init(), for instance. -// - -static void AllocateTLSOffset () -{ - int rslt ; - TSSA_Entry tssa ; - TSO_Entry tso ; - ptrdiff_t off ; - - guarantee (tlsMode == ThreadLocalStorage::pd_tlsAccessUndefined, "tlsMode not set") ; - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; - tlsOffset = 0 ; -#ifndef AMD64 - - tssa = (TSSA_Entry) dlsym (RTLD_DEFAULT, "thr_slot_sync_allocate") ; - if (tssa != NULL) { - off = -1 ; - rslt = (*tssa)(&off, NULL, NULL) ; // (off,dtor,darg) - if (off != -1) { - tlsOffset = off ; - tlsMode = ThreadLocalStorage::pd_tlsAccessIndirect ; - return ; - } - } - - rslt = thr_keycreate (&tlsKey, NULL) ; - if (rslt != 0) { - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; // revert to slow mode - return ; - } - - tso = (TSO_Entry) dlsym (RTLD_DEFAULT, "_thr_slot_offset") ; - if (tso != NULL) { - off = (*tso)(tlsKey) ; - if (off >= 0) { - tlsOffset = off ; - tlsMode = ThreadLocalStorage::pd_tlsAccessDirect ; - return ; - } - } - - // Failure: Too bad ... we've allocated a TLS slot we don't need and there's - // no provision in the ABI for returning the slot. - // - // If we didn't find a slot then then: - // 1. We might be on liblwp. - // 2. We might be on T2 libthread, but all "fast" slots are already - // consumed - // 3. We might be on T1, and all TSD (thr_slot_sync_allocate) slots are - // consumed. - // 4. We might be on T2 libthread, but it's be re-architected - // so that fast slots are no longer g7-relative. - // - - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; - return ; -#endif // AMD64 +bool ThreadLocalStorage::is_initialized() { + return _initialized; } -void ThreadLocalStorage::generate_code_for_get_thread() { - AllocateTLSOffset() ; +Thread* ThreadLocalStorage::get_thread_slow() { + return thread(); } -void ThreadLocalStorage::set_thread_in_slot(Thread *thread) { - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - if (tlsMode == pd_tlsAccessIndirect) { -#ifdef AMD64 - intptr_t tbase = fs_thread(); -#else - intptr_t tbase = gs_thread(); -#endif // AMD64 - *((Thread**) (tbase + tlsOffset)) = thread ; - } else - if (tlsMode == pd_tlsAccessDirect) { - thr_setspecific (tlsKey, (void *) thread) ; - // set with thr_setspecific and then readback with gs_load to validate. -#ifdef AMD64 - guarantee (thread == fs_load(tlsOffset), "tls readback failure") ; -#else - guarantee (thread == gs_load(tlsOffset), "tls readback failure") ; -#endif // AMD64 - } -} - - extern "C" Thread* get_thread() { return ThreadLocalStorage::thread(); }
--- a/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -25,61 +25,15 @@ #ifndef OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP #define OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP -// Processor dependent parts of ThreadLocalStorage +// Solaris specific implementation involves simple, direct use +// of a compiler-based thread-local variable private: - static Thread* _get_thread_cache[]; // index by [(raw_id>>9)^(raw_id>>20) % _pd_cache_size] - static Thread* get_thread_via_cache_slowly(uintptr_t raw_id, int index); + static __thread Thread * _thr_current; - NOT_PRODUCT(static int _tcacheHit;) - NOT_PRODUCT(static int _tcacheMiss;) + static bool _initialized; // needed for shared API public: - // Cache hit/miss statistics - static void print_statistics() PRODUCT_RETURN; - - enum Constants { -#ifdef AMD64 - _pd_cache_size = 256*2 // projected typical # of threads * 2 -#else - _pd_cache_size = 128*2 // projected typical # of threads * 2 -#endif // AMD64 - }; - - enum pd_tlsAccessMode { - pd_tlsAccessUndefined = -1, - pd_tlsAccessSlow = 0, - pd_tlsAccessIndirect = 1, - pd_tlsAccessDirect = 2 - } ; - - static void set_thread_in_slot (Thread *) ; - - static pd_tlsAccessMode pd_getTlsAccessMode () ; - static ptrdiff_t pd_getTlsOffset () ; - - static uintptr_t pd_raw_thread_id() { -#ifdef _GNU_SOURCE -#ifdef AMD64 - uintptr_t rv; - __asm__ __volatile__ ("movq %%fs:0, %0" : "=r"(rv)); - return rv; -#else - return gs_thread(); -#endif // AMD64 -#else //_GNU_SOURCE - return _raw_thread_id(); -#endif //_GNU_SOURCE - } - - static int pd_cache_index(uintptr_t raw_id) { - // Copied from the sparc version. Dave said it should also work fine - // for solx86. - int ix = (int) (((raw_id >> 9) ^ (raw_id >> 20)) % _pd_cache_size); - return ix; - } - - // Java Thread static inline Thread* thread(); #endif // OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP
--- a/src/share/vm/c1/c1_Canonicalizer.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -265,7 +265,8 @@ // limit this optimization to current block if (value != NULL && in_current_block(conv)) { set_canonical(new StoreIndexed(x->array(), x->index(), x->length(), - x->elt_type(), value, x->state_before())); + x->elt_type(), value, x->state_before(), + x->check_boolean())); return; } }
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -975,7 +975,19 @@ (array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant())) { length = append(new ArrayLength(array, state_before)); } - StoreIndexed* result = new StoreIndexed(array, index, length, type, value, state_before); + ciType* array_type = array->declared_type(); + bool check_boolean = false; + if (array_type != NULL) { + if (array_type->is_loaded() && + array_type->as_array_klass()->element_type()->basic_type() == T_BOOLEAN) { + assert(type == T_BYTE, "boolean store uses bastore"); + Value mask = append(new Constant(new IntConstant(1))); + value = append(new LogicOp(Bytecodes::_iand, value, mask)); + } + } else if (type == T_BYTE) { + check_boolean = true; + } + StoreIndexed* result = new StoreIndexed(array, index, length, type, value, state_before, check_boolean); append(result); _memory->store_value(value); @@ -1440,6 +1452,36 @@ need_mem_bar = true; } + BasicType bt = method()->return_type()->basic_type(); + switch (bt) { + case T_BYTE: + { + Value shift = append(new Constant(new IntConstant(24))); + x = append(new ShiftOp(Bytecodes::_ishl, x, shift)); + x = append(new ShiftOp(Bytecodes::_ishr, x, shift)); + break; + } + case T_SHORT: + { + Value shift = append(new Constant(new IntConstant(16))); + x = append(new ShiftOp(Bytecodes::_ishl, x, shift)); + x = append(new ShiftOp(Bytecodes::_ishr, x, shift)); + break; + } + case T_CHAR: + { + Value mask = append(new Constant(new IntConstant(0xFFFF))); + x = append(new LogicOp(Bytecodes::_iand, x, mask)); + break; + } + case T_BOOLEAN: + { + Value mask = append(new Constant(new IntConstant(1))); + x = append(new LogicOp(Bytecodes::_iand, x, mask)); + break; + } + } + // Check to see whether we are inlining. If so, Return // instructions become Gotos to the continuation point. if (continuation() != NULL) { @@ -1587,6 +1629,10 @@ if (state_before == NULL) { state_before = copy_state_for_exception(); } + if (field->type()->basic_type() == T_BOOLEAN) { + Value mask = append(new Constant(new IntConstant(1))); + val = append(new LogicOp(Bytecodes::_iand, val, mask)); + } append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching)); } break; @@ -1657,6 +1703,10 @@ if (state_before == NULL) { state_before = copy_state_for_exception(); } + if (field->type()->basic_type() == T_BOOLEAN) { + Value mask = append(new Constant(new IntConstant(1))); + val = append(new LogicOp(Bytecodes::_iand, val, mask)); + } StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching); if (!needs_patching) store = _memory->store(store); if (store != NULL) { @@ -4224,7 +4274,12 @@ #ifndef _LP64 offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); #endif - Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, args->at(3), is_volatile)); + Value val = args->at(3); + if (t == T_BOOLEAN) { + Value mask = append(new Constant(new IntConstant(1))); + val = append(new LogicOp(Bytecodes::_iand, val, mask)); + } + Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, val, is_volatile)); compilation()->set_has_unsafe_access(true); kill_all(); }
--- a/src/share/vm/c1/c1_Instruction.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_Instruction.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -976,11 +976,13 @@ ciMethod* _profiled_method; int _profiled_bci; + bool _check_boolean; + public: // creation - StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before) + StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before, bool check_boolean) : AccessIndexed(array, index, length, elt_type, state_before) - , _value(value), _profiled_method(NULL), _profiled_bci(0) + , _value(value), _profiled_method(NULL), _profiled_bci(0), _check_boolean(check_boolean) { set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object())); set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object())); @@ -992,6 +994,7 @@ Value value() const { return _value; } bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); } + bool check_boolean() const { return _check_boolean; } // Helpers for MethodData* profiling void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } void set_profiled_method(ciMethod* method) { _profiled_method = method; }
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 @@ -3646,3 +3646,26 @@ } } } + +LIR_Opr LIRGenerator::maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) { + if (x->check_boolean()) { + LIR_Opr value_fixed = rlock_byte(T_BYTE); + if (TwoOperandLIRForm) { + __ move(value, value_fixed); + __ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed); + } else { + __ logical_and(value, LIR_OprFact::intConst(1), value_fixed); + } + LIR_Opr klass = new_register(T_METADATA); + __ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info); + null_check_info = NULL; + LIR_Opr layout = new_register(T_INT); + __ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout); + int diffbit = Klass::layout_helper_boolean_diffbit(); + __ logical_and(layout, LIR_OprFact::intConst(diffbit), layout); + __ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0)); + __ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE); + value = value_fixed; + } + return value; +}
--- a/src/share/vm/c1/c1_LIRGenerator.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 @@ -445,6 +445,7 @@ void profile_arguments(ProfileCall* x); void profile_parameters(Base* x); void profile_parameters_at_call(ProfileCall* x); + LIR_Opr maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info); public: Compilation* compilation() const { return _compilation; }
--- a/src/share/vm/c1/c1_ValueType.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/c1/c1_ValueType.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -153,7 +153,19 @@ case T_FLOAT : return new FloatConstant (value.as_float ()); case T_DOUBLE : return new DoubleConstant(value.as_double()); case T_ARRAY : // fall through (ciConstant doesn't have an array accessor) - case T_OBJECT : return new ObjectConstant(value.as_object()); + case T_OBJECT : { + // TODO: Common the code with GraphBuilder::load_constant? + ciObject* obj = value.as_object(); + if (obj->is_null_object()) + return objectNull; + if (obj->is_loaded()) { + if (obj->is_array()) + return new ArrayConstant(obj->as_array()); + else if (obj->is_instance()) + return new InstanceConstant(obj->as_instance()); + } + return new ObjectConstant(obj); + } } ShouldNotReachHere(); return illegalType;
--- a/src/share/vm/ci/ciField.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/ci/ciField.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -187,6 +187,14 @@ // Even if general trusting is disabled, trust system-built closures in these packages. if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke")) return true; + // Trust Atomic*FieldUpdaters: they are very important for performance, and make up one + // more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483. + if (holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) { + return true; + } return TrustFinalNonStaticFields; }
--- a/src/share/vm/classfile/classFileParser.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/classFileParser.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -2423,11 +2423,9 @@ m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); -#ifdef CC_INTERP - // hmm is there a gc issue here?? + ResultTypeFinder rtf(_cp->symbol_at(signature_index)); - m->set_result_index(rtf.type()); -#endif + m->constMethod()->set_result_type(rtf.type()); if (args_size >= 0) { m->set_size_of_parameters(args_size);
--- a/src/share/vm/classfile/classLoader.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/classLoader.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -414,30 +414,30 @@ } #endif -void ClassLoader::trace_class_path(const char* msg, const char* name) { +void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { if (!TraceClassPaths) { return; } if (msg) { - tty->print("%s", msg); + out->print("%s", msg); } if (name) { if (strlen(name) < 256) { - tty->print("%s", name); + out->print("%s", name); } else { // For very long paths, we need to print each character separately, // as print_cr() has a length limit while (name[0] != '\0') { - tty->print("%c", name[0]); + out->print("%c", name[0]); name++; } } } if (msg && msg[0] == '[') { - tty->print_cr("]"); + out->print_cr("]"); } else { - tty->cr(); + out->cr(); } } @@ -583,7 +583,7 @@ // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily // the same as the bootcp of the shared archive. } else { - trace_class_path("[Bootstrap loader class path=", sys_class_path); + trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) {
--- a/src/share/vm/classfile/classLoader.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/classLoader.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -346,7 +346,7 @@ static void exit_with_path_failure(const char* error, const char* message); #endif - static void trace_class_path(const char* msg, const char* name = NULL); + static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); // VM monitoring and management support static jlong classloader_time_ms();
--- a/src/share/vm/classfile/defaultMethods.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/defaultMethods.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. 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 @@ -892,10 +892,8 @@ m->set_constants(NULL); // This will get filled in later m->set_name_index(cp->utf8(name)); m->set_signature_index(cp->utf8(sig)); -#ifdef CC_INTERP ResultTypeFinder rtf(sig); - m->set_result_index(rtf.type()); -#endif + m->constMethod()->set_result_type(rtf.type()); m->set_size_of_parameters(params); m->set_max_stack(max_stack); m->set_max_locals(params);
--- a/src/share/vm/classfile/sharedPathsMiscInfo.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. 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 @@ -67,7 +67,7 @@ } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); MetaspaceShared::set_archive_loading_failed(); return false; }
--- a/src/share/vm/classfile/sharedPathsMiscInfo.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ bool read(void* ptr, size_t size); static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); } protected: static bool fail(const char* msg, const char* name = NULL);
--- a/src/share/vm/classfile/stackMapTable.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/stackMapTable.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -186,7 +186,6 @@ u2 offset = _stream->get_u2(THREAD); if (offset >= _code_length || _code_data[offset] != ClassVerifier::NEW_OFFSET) { - ResourceMark rm(THREAD); _verifier->class_format_error( "StackMapTable format error: bad offset for Uninitialized"); return VerificationType::bogus_type();
--- a/src/share/vm/classfile/vmSymbols.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -204,7 +204,11 @@ template(java_lang_StackTraceElement, "java/lang/StackTraceElement") \ \ /* Concurrency support */ \ - template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ + template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ + template(java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl") \ + template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \ + template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \ + template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \ template(sun_misc_Contended_signature, "Lsun/misc/Contended;") \ \ /* class symbols needed by intrinsics */ \
--- a/src/share/vm/code/codeCache.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/codeCache.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -521,15 +521,17 @@ void CodeCache::gc_epilogue() { assert_locked_or_safepoint(CodeCache_lock); - FOR_ALL_ALIVE_BLOBS(cb) { - if (cb->is_nmethod()) { - nmethod *nm = (nmethod*)cb; - assert(!nm->is_unloaded(), "Tautology"); - if (needs_cache_clean()) { - nm->cleanup_inline_caches(); + NOT_DEBUG(if (needs_cache_clean())) { + FOR_ALL_ALIVE_BLOBS(cb) { + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + assert(!nm->is_unloaded(), "Tautology"); + DEBUG_ONLY(if (needs_cache_clean())) { + nm->cleanup_inline_caches(); + } + DEBUG_ONLY(nm->verify()); + DEBUG_ONLY(nm->verify_oop_relocations()); } - DEBUG_ONLY(nm->verify()); - DEBUG_ONLY(nm->verify_oop_relocations()); } } set_needs_cache_clean(false); @@ -734,27 +736,6 @@ return number_of_marked_CodeBlobs; } -void CodeCache::make_marked_nmethods_zombies() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - FOR_ALL_ALIVE_NMETHODS(nm) { - if (nm->is_marked_for_deoptimization()) { - - // If the nmethod has already been made non-entrant and it can be converted - // then zombie it now. Otherwise make it non-entrant and it will eventually - // be zombied when it is no longer seen on the stack. Note that the nmethod - // might be "entrant" and not on the stack and so could be zombied immediately - // but we can't tell because we don't track it on stack until it becomes - // non-entrant. - - if (nm->is_not_entrant() && nm->can_not_entrant_be_converted()) { - nm->make_zombie(); - } else { - nm->make_not_entrant(); - } - } - } -} - void CodeCache::make_marked_nmethods_not_entrant() { assert_locked_or_safepoint(CodeCache_lock); FOR_ALL_ALIVE_NMETHODS(nm) {
--- a/src/share/vm/code/codeCache.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/codeCache.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -179,7 +179,6 @@ static void mark_all_nmethods_for_deoptimization(); static int mark_for_deoptimization(Method* dependee); - static void make_marked_nmethods_zombies(); static void make_marked_nmethods_not_entrant(); // tells how many nmethods have dependencies
--- a/src/share/vm/code/compiledIC.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/compiledIC.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -155,6 +155,14 @@ return _ic_call->destination(); } +// Clears the IC stub if the compiled IC is in transition state +void CompiledIC::clear_ic_stub() { + if (is_in_transition_state()) { + ICStub* stub = ICStub_from_destination_address(stub_address()); + stub->clear(); + } +} + //----------------------------------------------------------------------------- // High-level access to an inline cache. Guaranteed to be MT-safe. @@ -281,6 +289,7 @@ assert( is_c1_or_jvmci_method || !is_monomorphic || is_optimized() || + !caller->is_alive() || (cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check"); #endif // ASSERT return is_monomorphic; @@ -315,7 +324,7 @@ } -void CompiledIC::set_to_clean() { +void CompiledIC::set_to_clean(bool in_use) { assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call"); if (TraceInlineCacheClearing || TraceICs) { tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); @@ -331,17 +340,14 @@ // A zombie transition will always be safe, since the metadata has already been set to NULL, so // we only need to patch the destination - bool safe_transition = is_optimized() || SafepointSynchronize::is_at_safepoint(); + bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint(); if (safe_transition) { // Kill any leftover stub we might have too - if (is_in_transition_state()) { - ICStub* old_stub = ICStub_from_destination_address(stub_address()); - old_stub->clear(); - } + clear_ic_stub(); if (is_optimized()) { - set_ic_destination(entry); - } else { + set_ic_destination(entry); + } else { set_ic_destination_and_value(entry, (void*)NULL); } } else {
--- a/src/share/vm/code/compiledIC.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/compiledIC.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -228,8 +228,9 @@ // // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full. // - void set_to_clean(); // Can only be called during a safepoint operation + void set_to_clean(bool in_use = true); void set_to_monomorphic(CompiledICInfo& info); + void clear_ic_stub(); // Returns true if successful and false otherwise. The call can fail if memory // allocation in the code cache fails.
--- a/src/share/vm/code/nmethod.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/nmethod.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1271,9 +1271,20 @@ } } +// Clear ICStubs of all compiled ICs +void nmethod::clear_ic_stubs() { + assert_locked_or_safepoint(CompiledIC_lock); + RelocIterator iter(this); + while(iter.next()) { + if (iter.type() == relocInfo::virtual_call_type) { + CompiledIC* ic = CompiledIC_at(&iter); + ic->clear_ic_stub(); + } + } +} + void nmethod::cleanup_inline_caches() { - assert_locked_or_safepoint(CompiledIC_lock); // If the method is not entrant or zombie then a JMP is plastered over the @@ -1289,7 +1300,8 @@ // In fact, why are we bothering to look at oops in a non-entrant method?? } - // Find all calls in an nmethod, and clear the ones that points to zombie methods + // Find all calls in an nmethod and clear the ones that point to non-entrant, + // zombie and unloaded nmethods. ResourceMark rm; RelocIterator iter(this, low_boundary); while(iter.next()) { @@ -1301,8 +1313,8 @@ CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination()); if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; - // Clean inline caches pointing to both zombie and not_entrant methods - if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(); + // Clean inline caches pointing to zombie, non-entrant and unloaded methods + if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive()); } break; } @@ -1311,7 +1323,7 @@ CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination()); if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; - // Clean inline caches pointing to both zombie and not_entrant methods + // Clean inline caches pointing to zombie, non-entrant and unloaded methods if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean(); } break; @@ -1402,7 +1414,7 @@ // Tell if a non-entrant method can be converted to a zombie (i.e., // there are no activations on the stack, not in use by the VM, // and not in use by the ServiceThread) -bool nmethod::can_not_entrant_be_converted() { +bool nmethod::can_convert_to_zombie() { assert(is_not_entrant(), "must be a non-entrant method"); // Since the nmethod sweeper only does partial sweep the sweeper's traversal @@ -1752,7 +1764,11 @@ // During GC the is_alive closure is non-NULL, and is used to // determine liveness of dependees that need to be updated. if (is_alive == NULL || klass->is_loader_alive(is_alive)) { - InstanceKlass::cast(klass)->remove_dependent_nmethod(this); + // The GC defers deletion of this entry, since there might be multiple threads + // iterating over the _dependencies graph. Other call paths are single-threaded + // and may delete it immediately. + bool delete_immediately = is_alive == NULL; + InstanceKlass::cast(klass)->remove_dependent_nmethod(this, delete_immediately); } } } @@ -2906,7 +2922,7 @@ // Hmm. OSR methods can be deopted but not marked as zombie or not_entrant // seems odd. - if( is_zombie() || is_not_entrant() ) + if (is_zombie() || is_not_entrant() || is_unloaded()) return; // Make sure all the entry points are correctly aligned for patching.
--- a/src/share/vm/code/nmethod.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/code/nmethod.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -594,6 +594,7 @@ // Inline cache support void clear_inline_caches(); + void clear_ic_stubs(); void cleanup_inline_caches(); bool inlinecache_check_contains(address addr) const { return (addr >= code_begin() && addr < verified_entry_point()); @@ -621,7 +622,7 @@ // See comment at definition of _last_seen_on_stack void mark_as_seen_on_stack(); - bool can_not_entrant_be_converted(); + bool can_convert_to_zombie(); // Evolution support. We make old (discarded) compiled methods point to new Method*s. void set_method(Method* method) { _method = method; }
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -2335,6 +2335,7 @@ case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent; case GCCause::_g1_humongous_allocation: return true; case GCCause::_update_allocation_context_stats_inc: return true; + case GCCause::_wb_conc_mark: return true; default: return false; } } @@ -3771,6 +3772,9 @@ _dcq.enqueue(card_ptr); } } + assert(hrrs.n_yielded() == r->rem_set()->occupied(), + err_msg("Remembered set hash maps out of sync, cur: " SIZE_FORMAT " entries, next: " SIZE_FORMAT " entries", + hrrs.n_yielded(), r->rem_set()->occupied())); r->rem_set()->clear_locked(); } assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); @@ -3840,6 +3844,16 @@ _surviving_young_words = NULL; } +class VerifyRegionRemSetClosure : public HeapRegionClosure { + public: + bool doHeapRegion(HeapRegion* hr) { + if (!hr->continuesHumongous()) { + hr->verify_rem_set(); + } + return false; + } +}; + #ifdef ASSERT class VerifyCSetClosure: public HeapRegionClosure { public: @@ -4016,6 +4030,14 @@ increment_total_collections(false /* full gc */); increment_gc_time_stamp(); + if (VerifyRememberedSets) { + if (!VerifySilently) { + gclog_or_tty->print_cr("[Verifying RemSets before GC]"); + } + VerifyRegionRemSetClosure v_cl; + heap_region_iterate(&v_cl); + } + verify_before_gc(); check_bitmaps("GC Start"); @@ -4095,6 +4117,13 @@ g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info); + // Make sure the remembered sets are up to date. This needs to be + // done before register_humongous_regions_with_cset(), because the + // remembered sets are used there to choose eager reclaim candidates. + // If the remembered sets are not up to date we might miss some + // entries that need to be handled. + g1_rem_set()->cleanupHRRS(); + register_humongous_regions_with_in_cset_fast_test(); assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); @@ -4242,6 +4271,14 @@ // scanning cards (see CR 7039627). increment_gc_time_stamp(); + if (VerifyRememberedSets) { + if (!VerifySilently) { + gclog_or_tty->print_cr("[Verifying RemSets after GC]"); + } + VerifyRegionRemSetClosure v_cl; + heap_region_iterate(&v_cl); + } + verify_after_gc(); check_bitmaps("GC End"); @@ -5052,12 +5089,8 @@ public: void clean_klass(InstanceKlass* ik) { - ik->clean_implementors_list(_is_alive); - ik->clean_method_data(_is_alive); - - // G1 specific cleanup work that has - // been moved here to be done in parallel. - ik->clean_dependent_nmethods(); + ik->clean_weak_instanceklass_links(_is_alive); + if (JvmtiExport::has_redefined_a_class()) { InstanceKlass::purge_previous_versions(ik); }
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -335,7 +335,6 @@ } void G1RemSet::prepare_for_oops_into_collection_set_do() { - cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs();
--- a/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -117,7 +117,7 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) : _g1h(g1h), - _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)), + _process_strong_tasks(G1RP_PS_NumElements), _srs(g1h), _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false), _n_workers_discovered_strong_classes(0) {} @@ -165,7 +165,7 @@ process_vm_roots(strong_roots, weak_roots, phase_times, worker_i); #if INCLUDE_JVMCI - if (trace_codecache && !_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) { + if (trace_codecache && !_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) { CodeCache::blobs_do(&root_code_blobs); } #endif @@ -173,7 +173,7 @@ { // Now the CM ref_processor roots. G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CMRefRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_refProcessor_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_refProcessor_oops_do)) { // We need to treat the discovered reference lists of the // concurrent mark ref processor as roots and keep entries // (which are added by the marking threads) on them live @@ -216,12 +216,12 @@ // as implicitly live). { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) { JavaThread::satb_mark_queue_set().filter_thread_buffers(); } } - _process_strong_tasks->all_tasks_completed(); + _process_strong_tasks.all_tasks_completed(); } void G1RootProcessor::process_strong_roots(OopClosure* oops, @@ -231,7 +231,7 @@ process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0); process_vm_roots(oops, NULL, NULL, 0); - _process_strong_tasks->all_tasks_completed(); + _process_strong_tasks.all_tasks_completed(); } void G1RootProcessor::process_all_roots(OopClosure* oops, @@ -241,11 +241,11 @@ process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0); process_vm_roots(oops, oops, NULL, 0); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) { CodeCache::blobs_do(blobs); } - _process_strong_tasks->all_tasks_completed(); + _process_strong_tasks.all_tasks_completed(); } void G1RootProcessor::process_java_roots(OopClosure* strong_roots, @@ -261,7 +261,7 @@ // let the thread process the weak CLDs and nmethods. { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) { ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds); } } @@ -278,49 +278,49 @@ uint worker_i) { { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Universe_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Universe_oops_do)) { Universe::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JNIRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_JNIHandles_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_JNIHandles_oops_do)) { JNIHandles::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_i); - if (!_process_strong_tasks-> is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) { ObjectSynchronizer::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) { FlatProfiler::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Management_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) { Management::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JVMTIRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_jvmti_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_jvmti_oops_do)) { JvmtiExport::oops_do(strong_roots); } } { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i); - if (!_process_strong_tasks->is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) { SystemDictionary::roots_oops_do(strong_roots, weak_roots); } } @@ -348,5 +348,5 @@ } void G1RootProcessor::set_num_workers(int active_workers) { - _process_strong_tasks->set_n_threads(active_workers); + _process_strong_tasks.set_n_threads(active_workers); }
--- a/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -45,7 +45,7 @@ // worker thread call the process_roots methods. class G1RootProcessor : public StackObj { G1CollectedHeap* _g1h; - SubTasksDone* _process_strong_tasks; + SubTasksDone _process_strong_tasks; SharedHeap::StrongRootsScope _srs; // Used to implement the Thread work barrier.
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -639,8 +639,8 @@ G1OffsetTableContigSpace::print_on(st); } -class VerifyLiveClosure: public OopClosure { -private: +class G1VerificationClosure : public OopClosure { +protected: G1CollectedHeap* _g1h; CardTableModRefBS* _bs; oop _containing_obj; @@ -651,7 +651,7 @@ // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, // _vo == UseMarkWord -> use mark word from object header. - VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : + G1VerificationClosure(G1CollectedHeap* g1h, VerifyOption vo) : _g1h(g1h), _bs(NULL), _containing_obj(NULL), _failures(false), _n_failures(0), _vo(vo) { @@ -667,9 +667,6 @@ bool failures() { return _failures; } int n_failures() { return _n_failures; } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - void print_object(outputStream* out, oop obj) { #ifdef PRODUCT Klass* k = obj->klass(); @@ -679,19 +676,31 @@ obj->print_on(out); #endif // PRODUCT } +}; + +class VerifyLiveClosure : public G1VerificationClosure { +public: + VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {} + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } template <class T> void do_oop_work(T* p) { assert(_containing_obj != NULL, "Precondition"); assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), - "Precondition"); + "Precondition"); + verify_liveness(p); + } + + template <class T> + void verify_liveness(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); bool failed = false; if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); + Mutex::_no_safepoint_check_flag); if (!_failures) { gclog_or_tty->cr(); @@ -727,50 +736,71 @@ failed = true; _n_failures++; } + } + } +}; - if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) { - HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - HeapRegion* to = _g1h->heap_region_containing(obj); - if (from != NULL && to != NULL && - from != to && - !to->isHumongous()) { - jbyte cv_obj = *_bs->byte_for_const(_containing_obj); - jbyte cv_field = *_bs->byte_for_const(p); - const jbyte dirty = CardTableModRefBS::dirty_card_val(); +class VerifyRemSetClosure : public G1VerificationClosure { +public: + VerifyRemSetClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {} + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } + + template <class T> + void do_oop_work(T* p) { + assert(_containing_obj != NULL, "Precondition"); + assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), + "Precondition"); + verify_remembered_set(p); + } - bool is_bad = !(from->is_young() - || to->rem_set()->contains_reference(p) - || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed - (_containing_obj->is_objArray() ? - cv_field == dirty - : cv_obj == dirty || cv_field == dirty)); - if (is_bad) { - MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); + template <class T> + void verify_remembered_set(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + bool failed = false; + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + HeapRegion* to = _g1h->heap_region_containing(obj); + if (from != NULL && to != NULL && + from != to && + !to->isHumongous()) { + jbyte cv_obj = *_bs->byte_for_const(_containing_obj); + jbyte cv_field = *_bs->byte_for_const(p); + const jbyte dirty = CardTableModRefBS::dirty_card_val(); - if (!_failures) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("----------"); - } - gclog_or_tty->print_cr("Missing rem set entry:"); - gclog_or_tty->print_cr("Field "PTR_FORMAT" " - "of obj "PTR_FORMAT", " - "in region "HR_FORMAT, - p, (void*) _containing_obj, - HR_FORMAT_PARAMS(from)); - _containing_obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("points to obj "PTR_FORMAT" " - "in region "HR_FORMAT, - (void*) obj, - HR_FORMAT_PARAMS(to)); - obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", - cv_obj, cv_field); + bool is_bad = !(from->is_young() + || to->rem_set()->contains_reference(p) + || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed + (_containing_obj->is_objArray() ? + cv_field == dirty + : cv_obj == dirty || cv_field == dirty)); + if (is_bad) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + + if (!_failures) { + gclog_or_tty->cr(); gclog_or_tty->print_cr("----------"); - gclog_or_tty->flush(); - _failures = true; - if (!failed) _n_failures++; } + gclog_or_tty->print_cr("Missing rem set entry:"); + gclog_or_tty->print_cr("Field "PTR_FORMAT" " + "of obj "PTR_FORMAT", " + "in region "HR_FORMAT, + p, (void*) _containing_obj, + HR_FORMAT_PARAMS(from)); + _containing_obj->print_on(gclog_or_tty); + gclog_or_tty->print_cr("points to obj "PTR_FORMAT" " + "in region "HR_FORMAT, + (void*) obj, + HR_FORMAT_PARAMS(to)); + obj->print_on(gclog_or_tty); + gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", + cv_obj, cv_field); + gclog_or_tty->print_cr("----------"); + gclog_or_tty->flush(); + _failures = true; + if (!failed) _n_failures++; } } } @@ -787,6 +817,7 @@ HeapWord* p = bottom(); HeapWord* prev_p = NULL; VerifyLiveClosure vl_cl(g1, vo); + VerifyRemSetClosure vr_cl(g1, vo); bool is_humongous = isHumongous(); bool do_bot_verify = !is_young(); size_t object_num = 0; @@ -832,7 +863,23 @@ return; } else { vl_cl.set_containing_obj(obj); - obj->oop_iterate_no_header(&vl_cl); + if (!g1->full_collection() || G1VerifyRSetsDuringFullGC) { + // verify liveness and rem_set + vr_cl.set_containing_obj(obj); + G1Mux2Closure mux(&vl_cl, &vr_cl); + obj->oop_iterate_no_header(&mux); + + if (vr_cl.failures()) { + *failures = true; + } + if (G1MaxVerifyFailures >= 0 && + vr_cl.n_failures() >= G1MaxVerifyFailures) { + return; + } + } else { + // verify only liveness + obj->oop_iterate_no_header(&vl_cl); + } if (vl_cl.failures()) { *failures = true; } @@ -842,7 +889,7 @@ } } } else { - gclog_or_tty->print_cr(PTR_FORMAT" no an oop", (void *)obj); + gclog_or_tty->print_cr(PTR_FORMAT" not an oop", (void *)obj); *failures = true; return; } @@ -930,6 +977,46 @@ verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); } +void HeapRegion::verify_rem_set(VerifyOption vo, bool* failures) const { + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + *failures = false; + HeapWord* p = bottom(); + HeapWord* prev_p = NULL; + VerifyRemSetClosure vr_cl(g1, vo); + while (p < top()) { + oop obj = oop(p); + size_t obj_size = block_size(p); + + if (!g1->is_obj_dead_cond(obj, this, vo)) { + if (obj->is_oop()) { + vr_cl.set_containing_obj(obj); + obj->oop_iterate_no_header(&vr_cl); + + if (vr_cl.failures()) { + *failures = true; + } + if (G1MaxVerifyFailures >= 0 && + vr_cl.n_failures() >= G1MaxVerifyFailures) { + return; + } + } else { + gclog_or_tty->print_cr(PTR_FORMAT " not an oop", p2i(obj)); + *failures = true; + return; + } + } + + prev_p = p; + p += obj_size; + } +} + +void HeapRegion::verify_rem_set() const { + bool failures = false; + verify_rem_set(VerifyOption_G1UsePrevMarking, &failures); + guarantee(!failures, "HeapRegion RemSet verification failed"); +} + // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go // away eventually.
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -779,6 +779,9 @@ // Override; it uses the "prev" marking information virtual void verify() const; + + void verify_rem_set(VerifyOption vo, bool *failures) const; + void verify_rem_set() const; }; // HeapRegionClosure is used for iterating over regions.
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 @@ -119,7 +119,9 @@ public: - HeapRegion* hr() const { return _hr; } + HeapRegion* hr() const { + return (HeapRegion*) OrderAccess::load_ptr_acquire(&_hr); + } jint occupied() const { // Overkill, but if we ever need it... @@ -132,10 +134,12 @@ set_next(NULL); set_prev(NULL); } - _hr = hr; _collision_list_next = NULL; _occupied = 0; _bm.clear(); + // Make sure that the bitmap clearing above has been finished before publishing + // this PRT to concurrent threads. + OrderAccess::release_store_ptr(&_hr, hr); } void add_reference(OopOrNarrowOopStar from) { @@ -441,7 +445,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" from-card cache hit."); } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just found " PTR_FORMAT " in the FromCardCache", from)); return; } @@ -454,7 +458,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" coarse map hit."); } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just found " PTR_FORMAT " in the Coarse table", from)); return; } @@ -488,7 +492,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" added card to sparse table."); } - assert(contains_reference_locked(from), "We just added it!"); + assert(contains_reference_locked(from), err_msg("We just added " PTR_FORMAT " to the Sparse table", from)); return; } else { if (G1TraceHeapRegionRememberedSet) { @@ -547,7 +551,7 @@ hr()->bottom(), from); } } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just added " PTR_FORMAT " to the PRT", from)); } PerRegionTable*
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -90,12 +90,8 @@ void VM_G1IncCollectionPause::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - assert(!_should_initiate_conc_mark || - ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || - (_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent) || - _gc_cause == GCCause::_g1_humongous_allocation || - _gc_cause == GCCause::_update_allocation_context_stats_inc), - "only a GC locker, a System.gc(), stats update or a hum allocation induced GC should start a cycle"); + assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause), + "only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle"); if (_word_size > 0) { // An allocation has been requested. So, try to do that first.
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -348,7 +348,7 @@ HeapWord* _partial_obj_addr; region_sz_t _partial_obj_size; region_sz_t volatile _dc_and_los; - bool _blocks_filled; + bool volatile _blocks_filled; #ifdef ASSERT size_t _blocks_filled_count; // Number of block table fills. @@ -499,7 +499,9 @@ inline bool ParallelCompactData::RegionData::blocks_filled() const { - return _blocks_filled; + bool result = _blocks_filled; + OrderAccess::acquire(); + return result; } #ifdef ASSERT @@ -513,6 +515,7 @@ inline void ParallelCompactData::RegionData::set_blocks_filled() { + OrderAccess::release(); _blocks_filled = true; // Debug builds count the number of times the table was filled. DEBUG_ONLY(Atomic::inc_ptr(&_blocks_filled_count));
--- a/src/share/vm/gc_interface/gcCause.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_interface/gcCause.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -54,6 +54,9 @@ case _wb_young_gc: return "WhiteBox Initiated Young GC"; + case _wb_conc_mark: + return "WhiteBox Initiated Concurrent Mark"; + case _update_allocation_context_stats_inc: case _update_allocation_context_stats_full: return "Update Allocation Context Stats";
--- a/src/share/vm/gc_interface/gcCause.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/gc_interface/gcCause.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -47,6 +47,7 @@ _heap_inspection, _heap_dump, _wb_young_gc, + _wb_conc_mark, _update_allocation_context_stats_inc, _update_allocation_context_stats_full,
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 @@ -1780,8 +1780,19 @@ ((objArrayOop) arrObj)->obj_at_put(index, rhsObject); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3); } - CASE(_bastore): - ARRAY_STOREFROM32(T_BYTE, jbyte, "%d", STACK_INT, 0); + CASE(_bastore): { + ARRAY_INTRO(-3); + int item = STACK_INT(-1); + // if it is a T_BOOLEAN array, mask the stored value to 0/1 + if (arrObj->klass() == Universe::boolArrayKlassObj()) { + item &= 1; + } else { + assert(arrObj->klass() == Universe::byteArrayKlassObj(), + "should be byte array otherwise"); + } + ((typeArrayOop)arrObj)->byte_at_put(index, item); + UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3); + } CASE(_castore): ARRAY_STOREFROM32(T_CHAR, jchar, "%d", STACK_INT, 0); CASE(_sastore): @@ -2012,7 +2023,7 @@ } else if (tos_type == ltos) { SET_STACK_LONG(obj->long_field_acquire(field_offset), 0); MORE_STACK(1); - } else if (tos_type == btos) { + } else if (tos_type == btos || tos_type == ztos) { SET_STACK_INT(obj->byte_field_acquire(field_offset), -1); } else if (tos_type == ctos) { SET_STACK_INT(obj->char_field_acquire(field_offset), -1); @@ -2033,7 +2044,7 @@ } else if (tos_type == ltos) { SET_STACK_LONG(obj->long_field(field_offset), 0); MORE_STACK(1); - } else if (tos_type == btos) { + } else if (tos_type == btos || tos_type == ztos) { SET_STACK_INT(obj->byte_field(field_offset), -1); } else if (tos_type == ctos) { SET_STACK_INT(obj->char_field(field_offset), -1); @@ -2122,6 +2133,9 @@ obj->release_obj_field_put(field_offset, STACK_OBJECT(-1)); } else if (tos_type == btos) { obj->release_byte_field_put(field_offset, STACK_INT(-1)); + } else if (tos_type == ztos) { + int bool_field = STACK_INT(-1); // only store LSB + obj->release_byte_field_put(field_offset, (bool_field & 1)); } else if (tos_type == ltos) { obj->release_long_field_put(field_offset, STACK_LONG(-1)); } else if (tos_type == ctos) { @@ -2142,6 +2156,9 @@ obj->obj_field_put(field_offset, STACK_OBJECT(-1)); } else if (tos_type == btos) { obj->byte_field_put(field_offset, STACK_INT(-1)); + } else if (tos_type == ztos) { + int bool_field = STACK_INT(-1); // only store LSB + obj->byte_field_put(field_offset, (bool_field & 1)); } else if (tos_type == ltos) { obj->long_field_put(field_offset, STACK_LONG(-1)); } else if (tos_type == ctos) {
--- a/src/share/vm/interpreter/bytecodes.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/bytecodes.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -510,6 +510,7 @@ def(_fast_aputfield , "fast_aputfield" , "bJJ" , NULL , T_OBJECT , 0, true , _putfield ); def(_fast_bputfield , "fast_bputfield" , "bJJ" , NULL , T_INT , 0, true , _putfield ); + def(_fast_zputfield , "fast_zputfield" , "bJJ" , NULL , T_INT , 0, true , _putfield ); def(_fast_cputfield , "fast_cputfield" , "bJJ" , NULL , T_CHAR , 0, true , _putfield ); def(_fast_dputfield , "fast_dputfield" , "bJJ" , NULL , T_DOUBLE , 0, true , _putfield ); def(_fast_fputfield , "fast_fputfield" , "bJJ" , NULL , T_FLOAT , 0, true , _putfield );
--- a/src/share/vm/interpreter/bytecodes.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/bytecodes.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -256,6 +256,7 @@ _fast_aputfield , _fast_bputfield , + _fast_zputfield , _fast_cputfield , _fast_dputfield , _fast_fputfield ,
--- a/src/share/vm/interpreter/interpreterRuntime.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -1022,6 +1022,7 @@ switch(cp_entry->flag_state()) { case btos: // fall through + case ztos: // fall through case ctos: // fall through case stos: // fall through case itos: // fall through @@ -1058,7 +1059,8 @@ char sig_type = '\0'; switch(cp_entry->flag_state()) { - case btos: sig_type = 'Z'; break; + case btos: sig_type = 'B'; break; + case ztos: sig_type = 'Z'; break; case ctos: sig_type = 'C'; break; case stos: sig_type = 'S'; break; case itos: sig_type = 'I'; break;
--- a/src/share/vm/interpreter/templateInterpreter.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -61,8 +61,9 @@ // Implementation of EntryPoint EntryPoint::EntryPoint() { - assert(number_of_states == 9, "check the code below"); + assert(number_of_states == 10, "check the code below"); _entry[btos] = NULL; + _entry[ztos] = NULL; _entry[ctos] = NULL; _entry[stos] = NULL; _entry[atos] = NULL; @@ -74,9 +75,10 @@ } -EntryPoint::EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) { - assert(number_of_states == 9, "check the code below"); +EntryPoint::EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) { + assert(number_of_states == 10, "check the code below"); _entry[btos] = bentry; + _entry[ztos] = zentry; _entry[ctos] = centry; _entry[stos] = sentry; _entry[atos] = aentry; @@ -127,6 +129,7 @@ return EntryPoint( _table[btos][i], + _table[ztos][i], _table[ctos][i], _table[stos][i], _table[atos][i], @@ -141,8 +144,9 @@ void DispatchTable::set_entry(int i, EntryPoint& entry) { assert(0 <= i && i < length, "index out of bounds"); - assert(number_of_states == 9, "check the code below"); + assert(number_of_states == 10, "check the code below"); _table[btos][i] = entry.entry(btos); + _table[ztos][i] = entry.entry(ztos); _table[ctos][i] = entry.entry(ctos); _table[stos][i] = entry.entry(stos); _table[atos][i] = entry.entry(atos); @@ -225,6 +229,7 @@ Interpreter::_trace_code = EntryPoint( generate_trace_code(btos), + generate_trace_code(ztos), generate_trace_code(ctos), generate_trace_code(stos), generate_trace_code(atos), @@ -245,6 +250,7 @@ generate_return_entry_for(itos, i, index_size), generate_return_entry_for(itos, i, index_size), generate_return_entry_for(itos, i, index_size), + generate_return_entry_for(itos, i, index_size), generate_return_entry_for(atos, i, index_size), generate_return_entry_for(itos, i, index_size), generate_return_entry_for(ltos, i, index_size), @@ -256,13 +262,16 @@ } { CodeletMark cm(_masm, "invoke return entry points"); - const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos}; + // These states are in order specified in TosState, except btos/ztos/ctos/stos are + // really the same as itos since there is no top of stack optimization for these types + const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl}; const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic); const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface); const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic); for (int i = 0; i < Interpreter::number_of_return_addrs; i++) { TosState state = states[i]; + assert(state != ilgl, "states array is wrong above"); Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2)); Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2)); Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4)); @@ -273,6 +282,7 @@ Interpreter::_earlyret_entry = EntryPoint( generate_earlyret_entry_for(btos), + generate_earlyret_entry_for(ztos), generate_earlyret_entry_for(ctos), generate_earlyret_entry_for(stos), generate_earlyret_entry_for(atos), @@ -291,6 +301,7 @@ ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), ((InterpreterGenerator*)this)->generate_deopt_entry_for(atos, i), ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), ((InterpreterGenerator*)this)->generate_deopt_entry_for(ltos, i), @@ -318,6 +329,7 @@ Interpreter::_continuation_entry = EntryPoint( generate_continuation_for(btos), + generate_continuation_for(ztos), generate_continuation_for(ctos), generate_continuation_for(stos), generate_continuation_for(atos), @@ -333,6 +345,7 @@ Interpreter::_safept_entry = EntryPoint( generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), + generate_safept_entry_for(ztos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), @@ -436,7 +449,7 @@ void TemplateInterpreterGenerator::set_unimplemented(int i) { address e = _unimplemented_bytecode; - EntryPoint entry(e, e, e, e, e, e, e, e, e); + EntryPoint entry(e, e, e, e, e, e, e, e, e, e); Interpreter::_normal_table.set_entry(i, entry); Interpreter::_wentry_point[i] = _unimplemented_bytecode; } @@ -448,6 +461,7 @@ assert(_unimplemented_bytecode != NULL, "should have been generated before"); assert(_illegal_bytecode_sequence != NULL, "should have been generated before"); address bep = _illegal_bytecode_sequence; + address zep = _illegal_bytecode_sequence; address cep = _illegal_bytecode_sequence; address sep = _illegal_bytecode_sequence; address aep = _illegal_bytecode_sequence; @@ -469,7 +483,7 @@ set_wide_entry_point(t, wep); } // set entry points - EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep); + EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, vep); Interpreter::_normal_table.set_entry(code, entry); Interpreter::_wentry_point[code] = wep; } @@ -486,6 +500,7 @@ assert(t->is_valid(), "template must exist"); switch (t->tos_in()) { case btos: + case ztos: case ctos: case stos: ShouldNotReachHere(); // btos/ctos/stos should use itos.
--- a/src/share/vm/interpreter/templateInterpreter.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/templateInterpreter.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -44,7 +44,7 @@ public: // Construction EntryPoint(); - EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry); + EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry); // Attributes address entry(TosState state) const; // return target address for a given tosca state
--- a/src/share/vm/interpreter/templateTable.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/interpreter/templateTable.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -488,6 +488,7 @@ def(Bytecodes::_fast_aputfield , ubcp|____|____|____, atos, vtos, fast_storefield , atos ); def(Bytecodes::_fast_bputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos ); + def(Bytecodes::_fast_zputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos ); def(Bytecodes::_fast_cputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos ); def(Bytecodes::_fast_dputfield , ubcp|____|____|____, dtos, vtos, fast_storefield , dtos ); def(Bytecodes::_fast_fputfield , ubcp|____|____|____, ftos, vtos, fast_storefield , ftos );
--- a/src/share/vm/memory/universe.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/memory/universe.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -114,6 +114,7 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_pd_implies_cache = NULL; +LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; oop Universe::_out_of_memory_error_class_metaspace = NULL; @@ -129,7 +130,6 @@ oop Universe::_vm_exception = NULL; oop Universe::_allocation_context_notification_obj = NULL; -Method* Universe::_throw_illegal_access_error = NULL; Array<int>* Universe::_the_empty_int_array = NULL; Array<u2>* Universe::_the_empty_short_array = NULL; Array<Klass*>* Universe::_the_empty_klass_array = NULL; @@ -235,6 +235,7 @@ _finalizer_register_cache->serialize(f); _loader_addClass_cache->serialize(f); _pd_implies_cache->serialize(f); + _throw_illegal_access_error_cache->serialize(f); } void Universe::check_alignment(uintx size, uintx alignment, const char* name) { @@ -663,6 +664,7 @@ Universe::_finalizer_register_cache = new LatestMethodCache(); Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_pd_implies_cache = new LatestMethodCache(); + Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); if (UseSharedSpaces) { // Read the data structures supporting the shared spaces (shared @@ -847,12 +849,6 @@ // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. - bool verbose = PrintCompressedOopsMode || (PrintMiscellaneous && Verbose); - if (verbose) { - tty->cr(); - tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", - Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); - } if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) { // Can't reserve heap below 32Gb. // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() @@ -862,16 +858,8 @@ // are decoded so that NULL is preserved, so this page will not be accessed. Universe::set_narrow_oop_use_implicit_null_checks(false); #endif - if (verbose) { - tty->print(", %s: "PTR_FORMAT, - narrow_oop_mode_to_string(HeapBasedNarrowOop), - Universe::narrow_oop_base()); - } } else { Universe::set_narrow_oop_base(0); - if (verbose) { - tty->print(", %s", narrow_oop_mode_to_string(ZeroBasedNarrowOop)); - } #ifdef _WIN64 if (!Universe::narrow_oop_use_implicit_null_checks()) { // Don't need guard page for implicit checks in indexed addressing @@ -884,17 +872,14 @@ Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } else { Universe::set_narrow_oop_shift(0); - if (verbose) { - tty->print(", %s", narrow_oop_mode_to_string(UnscaledNarrowOop)); - } } } - if (verbose) { - tty->cr(); - tty->cr(); + Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); + + if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { + Universe::print_compressed_oops_mode(); } - Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); } // Universe::narrow_oop_base() is one page below the heap. assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - @@ -915,6 +900,24 @@ return JNI_OK; } +void Universe::print_compressed_oops_mode() { + tty->cr(); + tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", + Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); + + tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode())); + + if (Universe::narrow_oop_base() != 0) { + tty->print(":" PTR_FORMAT, Universe::narrow_oop_base()); + } + + if (Universe::narrow_oop_shift() != 0) { + tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift()); + } + + tty->cr(); + tty->cr(); +} // Reserve the Java heap, which is now the same for all GCs. ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { @@ -984,11 +987,11 @@ const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode) { switch (mode) { case UnscaledNarrowOop: - return "32-bits Oops"; + return "32-bit"; case ZeroBasedNarrowOop: - return "zero based Compressed Oops"; + return "Zero based"; case HeapBasedNarrowOop: - return "Compressed Oops with base"; + return "Non-zero based"; } ShouldNotReachHere(); @@ -1134,7 +1137,8 @@ tty->print_cr("Unable to link/verify Unsafe.throwIllegalAccessError method"); return false; // initialization failed (cannot throw exception yet) } - Universe::_throw_illegal_access_error = m; + Universe::_throw_illegal_access_error_cache->init( + SystemDictionary::misc_Unsafe_klass(), m); // Setup method for registering loaded classes in class loader vector InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->link_class(CHECK_false); @@ -1160,7 +1164,7 @@ return false; // initialization failed } Universe::_pd_implies_cache->init( - SystemDictionary::ProtectionDomain_klass(), m);; + SystemDictionary::ProtectionDomain_klass(), m); } // The folowing is initializing converter functions for serialization in
--- a/src/share/vm/memory/universe.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/memory/universe.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -148,8 +148,7 @@ static LatestMethodCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes - - static Method* _throw_illegal_access_error; + static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method // preallocated error objects (no backtrace) static oop _out_of_memory_error_java_heap; @@ -305,6 +304,7 @@ static Method* loader_addClass_method() { return _loader_addClass_cache->get_method(); } static Method* protection_domain_implies_method() { return _pd_implies_cache->get_method(); } + static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } @@ -314,8 +314,6 @@ static inline oop allocation_context_notification_obj(); static inline void set_allocation_context_notification_obj(oop obj); - static Method* throw_illegal_access_error() { return _throw_illegal_access_error; } - static Array<int>* the_empty_int_array() { return _the_empty_int_array; } static Array<u2>* the_empty_short_array() { return _the_empty_short_array; } static Array<Method*>* the_empty_method_array() { return _the_empty_method_array; } @@ -376,6 +374,8 @@ static void set_narrow_ptrs_base(address a) { _narrow_ptrs_base = a; } static address narrow_ptrs_base() { return _narrow_ptrs_base; } + static void print_compressed_oops_mode(); + // this is set in vm_version on sparc (and then reset in universe afaict) static void set_narrow_oop_shift(int shift) { _narrow_oop._shift = shift;
--- a/src/share/vm/oops/constMethod.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/constMethod.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -65,6 +65,7 @@ set_max_locals(0); set_method_idnum(0); set_size_of_parameters(0); + set_result_type(T_VOID); } // Accessor that copies to metadata.
--- a/src/share/vm/oops/constMethod.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/constMethod.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -211,6 +211,7 @@ int _constMethod_size; u2 _flags; + u1 _result_type; // BasicType of result // Size of Java bytecodes allocated immediately after Method*. u2 _code_size; @@ -469,6 +470,8 @@ static ByteSize size_of_parameters_offset() { return byte_offset_of(ConstMethod, _size_of_parameters); } + static ByteSize result_type_offset() + { return byte_offset_of(ConstMethod, _result_type); } // Unique id for the method static const u2 MAX_IDNUM; @@ -491,6 +494,8 @@ int size_of_parameters() const { return _size_of_parameters; } void set_size_of_parameters(int size) { _size_of_parameters = size; } + void set_result_type(BasicType rt) { assert(rt < 16, "result type too large"); + _result_type = (u1)rt; } // Deallocation for RedefineClasses void deallocate_contents(ClassLoaderData* loader_data); bool is_klass() const { return false; }
--- a/src/share/vm/oops/cpCache.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/cpCache.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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 @@ -77,18 +77,19 @@ // f2 flag true if f2 contains an oop (e.g., virtual final method) // fv flag true if invokeinterface used for method in class Object // -// The flags 31, 30, 29, 28 together build a 4 bit number 0 to 8 with the +// The flags 31, 30, 29, 28 together build a 4 bit number 0 to 16 with the // following mapping to the TosState states: // // btos: 0 -// ctos: 1 -// stos: 2 -// itos: 3 -// ltos: 4 -// ftos: 5 -// dtos: 6 -// atos: 7 -// vtos: 8 +// ztos: 1 +// ctos: 2 +// stos: 3 +// itos: 4 +// ltos: 5 +// ftos: 6 +// dtos: 7 +// atos: 8 +// vtos: 9 // // Entry specific: field entries: // _indices = get (b1 section) and put (b2 section) bytecodes, original constant pool index @@ -351,14 +352,8 @@ bool has_method_type() const { return (!is_f1_null()) && (_flags & (1 << has_method_type_shift)) != 0; } bool is_method_entry() const { return (_flags & (1 << is_field_entry_shift)) == 0; } bool is_field_entry() const { return (_flags & (1 << is_field_entry_shift)) != 0; } - bool is_byte() const { return flag_state() == btos; } - bool is_char() const { return flag_state() == ctos; } - bool is_short() const { return flag_state() == stos; } - bool is_int() const { return flag_state() == itos; } bool is_long() const { return flag_state() == ltos; } - bool is_float() const { return flag_state() == ftos; } bool is_double() const { return flag_state() == dtos; } - bool is_object() const { return flag_state() == atos; } TosState flag_state() const { assert((uint)number_of_states <= (uint)tos_state_mask+1, ""); return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
--- a/src/share/vm/oops/instanceKlass.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/instanceKlass.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1973,7 +1973,7 @@ // find a corresponding bucket otherwise there's a bug in the // recording of dependecies. // -void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { +void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { assert_locked_or_safepoint(CodeCache_lock); nmethodBucket* b = _dependencies; nmethodBucket* last = NULL; @@ -1982,7 +1982,17 @@ int val = b->decrement(); guarantee(val >= 0, err_msg("Underflow: %d", val)); if (val == 0) { - set_has_unloaded_dependent(true); + if (delete_immediately) { + if (last == NULL) { + _dependencies = b->next(); + } else { + last->set_next(b->next()); + } + delete b; + } else { + // The deletion of this entry is deferred until a later, potentially parallel GC phase. + set_has_unloaded_dependent(true); + } } return; } @@ -2322,6 +2332,13 @@ #endif // INCLUDE_ALL_GCS +void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) { + clean_implementors_list(is_alive); + clean_method_data(is_alive); + + clean_dependent_nmethods(); +} + void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) {
--- a/src/share/vm/oops/instanceKlass.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/instanceKlass.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -785,7 +785,7 @@ // maintenance of deoptimization dependencies int mark_dependent_nmethods(DepChange& changes); void add_dependent_nmethod(nmethod* nm); - void remove_dependent_nmethod(nmethod* nm); + void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); // On-stack replacement support nmethod* osr_nmethods_head() const { return _osr_nmethods_head; }; @@ -974,6 +974,7 @@ void oop_follow_contents(oop obj); int oop_adjust_pointers(oop obj); + void clean_weak_instanceklass_links(BoolObjectClosure* is_alive); void clean_implementors_list(BoolObjectClosure* is_alive); void clean_method_data(BoolObjectClosure* is_alive); void clean_dependent_nmethods();
--- a/src/share/vm/oops/klass.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/klass.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -454,8 +454,7 @@ // Clean the implementors list and method data. if (clean_alive_klasses && current->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(current); - ik->clean_implementors_list(is_alive); - ik->clean_method_data(is_alive); + ik->clean_weak_instanceklass_links(is_alive); } } }
--- a/src/share/vm/oops/klass.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/klass.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -370,6 +370,21 @@ assert(btvalue >= T_BOOLEAN && btvalue <= T_OBJECT, "sanity"); return (BasicType) btvalue; } + + // Want a pattern to quickly diff against layout header in register + // find something less clever! + static int layout_helper_boolean_diffbit() { + jint zlh = array_layout_helper(T_BOOLEAN); + jint blh = array_layout_helper(T_BYTE); + assert(zlh != blh, "array layout helpers must differ"); + int diffbit = 1; + while ((diffbit & (zlh ^ blh)) == 0 && (diffbit & zlh) == 0) { + diffbit <<= 1; + assert(diffbit != 0, "make sure T_BOOLEAN has a different bit than T_BYTE"); + } + return diffbit; + } + static int layout_helper_log2_element_size(jint lh) { assert(lh < (jint)_lh_neutral_value, "must be array"); int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask;
--- a/src/share/vm/oops/method.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/method.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -84,9 +84,6 @@ set_constMethod(xconst); set_access_flags(access_flags); set_method_size(size); -#ifdef CC_INTERP - set_result_index(T_VOID); -#endif set_intrinsic_id(vmIntrinsics::_none); set_jfr_towrite(false); set_force_inline(false); @@ -412,12 +409,6 @@ set_size_of_parameters(asc.size() + (is_static() ? 0 : 1)); } -#ifdef CC_INTERP -void Method::set_result_index(BasicType type) { - _result_index = Interpreter::BasicType_as_index(type); -} -#endif - BasicType Method::result_type() const { ResultTypeFinder rtf(signature()); return rtf.type(); @@ -1123,10 +1114,8 @@ m->set_signature_index(_imcp_invoke_signature); assert(MethodHandles::is_signature_polymorphic_name(m->name()), ""); assert(m->signature() == signature, ""); -#ifdef CC_INTERP ResultTypeFinder rtf(signature); - m->set_result_index(rtf.type()); -#endif + m->constMethod()->set_result_type(rtf.type()); m->compute_size_of_parameters(THREAD); m->init_intrinsic_id(); assert(m->is_method_handle_intrinsic(), "");
--- a/src/share/vm/oops/method.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/method.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -105,9 +105,6 @@ AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) // note: can have vtables with >2**16 elements (because of inheritance) -#ifdef CC_INTERP - int _result_index; // C++ interpreter needs for converting results to/from stack -#endif u2 _method_size; // size of this object u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) @@ -206,11 +203,6 @@ return constMethod()->type_annotations(); } -#ifdef CC_INTERP - void set_result_index(BasicType type); - int result_index() { return _result_index; } -#endif - // Helper routine: get klass name + "." + method name + signature as // C string, for the purpose of providing more useful NoSuchMethodErrors // and fatal error handling. The string is allocated in resource @@ -563,7 +555,6 @@ void compute_size_of_parameters(Thread *thread); // word size of parameters (receiver if any + arguments) Symbol* klass_name() const; // returns the name of the method holder BasicType result_type() const; // type of the method result - int result_type_index() const; // type index of the method result bool is_returning_oop() const { BasicType r = result_type(); return (r == T_OBJECT || r == T_ARRAY); } bool is_returning_fp() const { BasicType r = result_type(); return (r == T_FLOAT || r == T_DOUBLE); } @@ -656,9 +647,6 @@ // interpreter support static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); } static ByteSize access_flags_offset() { return byte_offset_of(Method, _access_flags ); } -#ifdef CC_INTERP - static ByteSize result_index_offset() { return byte_offset_of(Method, _result_index ); } -#endif /* CC_INTERP */ static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } static ByteSize method_data_offset() {
--- a/src/share/vm/oops/oop.inline.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/oop.inline.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -339,7 +339,7 @@ inline void oopDesc::byte_field_put(int offset, jbyte contents) { *byte_field_addr(offset) = (jint) contents; } inline jboolean oopDesc::bool_field(int offset) const { return (jboolean) *bool_field_addr(offset); } -inline void oopDesc::bool_field_put(int offset, jboolean contents) { *bool_field_addr(offset) = (jint) contents; } +inline void oopDesc::bool_field_put(int offset, jboolean contents) { *bool_field_addr(offset) = (( (jint) contents) & 1); } inline jchar oopDesc::char_field(int offset) const { return (jchar) *char_field_addr(offset); } inline void oopDesc::char_field_put(int offset, jchar contents) { *char_field_addr(offset) = (jint) contents; } @@ -379,7 +379,7 @@ inline void oopDesc::release_byte_field_put(int offset, jbyte contents) { OrderAccess::release_store(byte_field_addr(offset), contents); } inline jboolean oopDesc::bool_field_acquire(int offset) const { return OrderAccess::load_acquire(bool_field_addr(offset)); } -inline void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), contents); } +inline void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), (contents & 1)); } inline jchar oopDesc::char_field_acquire(int offset) const { return OrderAccess::load_acquire(char_field_addr(offset)); } inline void oopDesc::release_char_field_put(int offset, jchar contents) { OrderAccess::release_store(char_field_addr(offset), contents); }
--- a/src/share/vm/oops/typeArrayOop.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/oops/typeArrayOop.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -96,7 +96,7 @@ void byte_at_put(int which, jbyte contents) { *byte_at_addr(which) = contents; } jboolean bool_at(int which) const { return *bool_at_addr(which); } - void bool_at_put(int which, jboolean contents) { *bool_at_addr(which) = contents; } + void bool_at_put(int which, jboolean contents) { *bool_at_addr(which) = (((jint)contents) & 1); } jchar char_at(int which) const { return *char_at_addr(which); } void char_at_put(int which, jchar contents) { *char_at_addr(which) = contents; }
--- a/src/share/vm/opto/block.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/block.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -393,7 +393,7 @@ VectorSet visited(a); // Allocate stack with enough space to avoid frequent realloc - Node_Stack nstack(a, C->unique() >> 1); + Node_Stack nstack(a, C->live_nodes() >> 1); nstack.push(_root, 0); uint sum = 0; // Counter for blocks
--- a/src/share/vm/opto/c2_globals.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/c2_globals.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -205,6 +205,9 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseCountedLoopSafepoints, false, \ + "Force counted loops to keep a safepoint") \ + \ product(bool, UseLoopPredicate, true, \ "Generate a predicate to select fast/slow loop versions") \ \ @@ -669,6 +672,9 @@ product_pd(bool, TrapBasedRangeChecks, \ "Generate code for range checks that uses a cmp and trap " \ "instruction raising SIGTRAP. Used on PPC64.") \ + \ + develop(bool, RenumberLiveNodes, true, \ + "Renumber live nodes") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
--- a/src/share/vm/opto/cfgnode.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/cfgnode.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -791,7 +791,7 @@ Compile *C = igvn->C; Arena *a = Thread::current()->resource_area(); Node_Array node_map = new Node_Array(a); - Node_Stack stack(a, C->unique() >> 4); + Node_Stack stack(a, C->live_nodes() >> 4); PhiNode *nphi = slice_memory(at); igvn->register_new_node_with_optimizer( nphi ); node_map.map(_idx, nphi);
--- a/src/share/vm/opto/compile.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/compile.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -327,7 +327,7 @@ // Use breadth-first pass that records state in a Unique_Node_List, // recursive traversal is slower. void Compile::identify_useful_nodes(Unique_Node_List &useful) { - int estimated_worklist_size = unique(); + int estimated_worklist_size = live_nodes(); useful.map( estimated_worklist_size, NULL ); // preallocate space // Initialize worklist @@ -2093,6 +2093,20 @@ // so keep only the actual candidates for optimizations. cleanup_expensive_nodes(igvn); + if (!failing() && RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) { + NOT_PRODUCT(Compile::TracePhase t2("", &_t_renumberLive, TimeCompiler);) + initial_gvn()->replace_with(&igvn); + for_igvn()->clear(); + Unique_Node_List new_worklist(C->comp_arena()); + { + ResourceMark rm; + PhaseRenumberLive prl = PhaseRenumberLive(initial_gvn(), for_igvn(), &new_worklist); + } + set_for_igvn(&new_worklist); + igvn = PhaseIterGVN(initial_gvn()); + igvn.optimize(); + } + // Perform escape analysis if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { if (has_loops()) { @@ -3214,8 +3228,8 @@ Final_Reshape_Counts frc; // Visit everybody reachable! - // Allocate stack of size C->unique()/2 to avoid frequent realloc - Node_Stack nstack(unique() >> 1); + // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc + Node_Stack nstack(live_nodes() >> 1); final_graph_reshaping_walk(nstack, root(), frc); // Check for unreachable (from below) code (i.e., infinite loops).
--- a/src/share/vm/opto/domgraph.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/domgraph.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -505,8 +505,8 @@ // Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup // 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent. int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uint *dfsorder) { - // Allocate stack of size C->unique()/8 to avoid frequent realloc - GrowableArray <Node *> dfstack(pil->C->unique() >> 3); + // Allocate stack of size C->live_nodes()/8 to avoid frequent realloc + GrowableArray <Node *> dfstack(pil->C->live_nodes() >> 3); Node *b = pil->C->root(); int dfsnum = 1; dfsorder[b->_idx] = dfsnum; // Cache parent's dfsnum for a later use
--- a/src/share/vm/opto/escape.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/escape.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -3183,7 +3183,7 @@ // Note 2: MergeMem may already contains instance memory slices added // during find_inst_mem() call when memory nodes were processed above. igvn->hash_delete(nmm); - uint nslices = nmm->req(); + uint nslices = MIN2(nmm->req(), new_index_start); for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) { Node* mem = nmm->in(i); Node* cur = NULL;
--- a/src/share/vm/opto/gcm.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/gcm.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -118,8 +118,8 @@ //------------------------------schedule_pinned_nodes-------------------------- // Set the basic block for Nodes pinned into blocks void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) { - // Allocate node stack of size C->unique()+8 to avoid frequent realloc - GrowableArray <Node *> spstack(C->unique() + 8); + // Allocate node stack of size C->live_nodes()+8 to avoid frequent realloc + GrowableArray <Node *> spstack(C->live_nodes() + 8); spstack.push(_root); while (spstack.is_nonempty()) { Node* node = spstack.pop(); @@ -1285,7 +1285,7 @@ visited.Clear(); Node_List stack(arena); // Pre-grow the list - stack.map((C->unique() >> 1) + 16, NULL); + stack.map((C->live_nodes() >> 1) + 16, NULL); if (!schedule_early(visited, stack)) { // Bailout without retry C->record_method_not_compilable("early schedule failed");
--- a/src/share/vm/opto/loopTransform.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/loopTransform.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1739,6 +1739,12 @@ } return true; } + if (is_scaled_iv(exp->in(2), iv, p_scale)) { + if (p_offset != NULL) { + *p_offset = exp->in(1); + } + return true; + } if (exp->in(2)->is_Con()) { Node* offset2 = NULL; if (depth < 2 &&
--- a/src/share/vm/opto/loopnode.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/loopnode.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -685,14 +685,16 @@ } // LoopLimitCheck - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); + if (!UseCountedLoopSafepoints) { + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt); + } + loop->_tail = iftrue; } - loop->_tail = iftrue; } // Build a canonical trip test. @@ -781,12 +783,14 @@ lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceding SafePoint and remove - Node *sfpt2 = le->in(0); - if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + if (!UseCountedLoopSafepoints) { + // Check for immediately preceding SafePoint and remove + Node *sfpt2 = le->in(0); + if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { + lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt2); + } } } @@ -1806,6 +1810,37 @@ } } +void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { + Node* keep = NULL; + if (keep_one) { + // Look for a safepoint on the idom-path. + for (Node* i = tail(); i != _head; i = phase->idom(i)) { + if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { + keep = i; + break; // Found one + } + } + } + + // Don't remove any safepoints if it is requested to keep a single safepoint and + // no safepoint was found on idom-path. It is not safe to remove any safepoint + // in this case since there's no safepoint dominating all paths in the loop body. + bool prune = !keep_one || keep != NULL; + + // Delete other safepoints in this loop. + Node_List* sfpts = _safepts; + if (prune && sfpts != NULL) { + assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); + for (uint i = 0; i < sfpts->size(); i++) { + Node* n = sfpts->at(i); + assert(phase->get_loop(n) == this, ""); + if (n != keep && phase->is_deleteable_safept(n)) { + phase->lazy_replace(n, n->in(TypeFunc::Control)); + } + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { @@ -1817,42 +1852,23 @@ if (_head->is_CountedLoop() || phase->is_counted_loop(_head, this)) { - _has_sfpt = 1; // Indicate we do not need a safepoint here - - // Look for safepoints to remove. - Node_List* sfpts = _safepts; - if (sfpts != NULL) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } + + if (!UseCountedLoopSafepoints) { + // Indicate we do not need a safepoint here + _has_sfpt = 1; } + // Remove safepoints + bool keep_one_sfpt = !(_has_call || _has_sfpt); + remove_safepoints(phase, keep_one_sfpt); + // Look for induction variables phase->replace_parallel_iv(this); } else if (_parent != NULL && !_irreducible) { - // Not a counted loop. - // Look for a safepoint on the idom-path. - Node* sfpt = tail(); - for (; sfpt != _head; sfpt = phase->idom(sfpt)) { - if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this) - break; // Found one - } - // Delete other safepoints in this loop. - Node_List* sfpts = _safepts; - if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (n != sfpt && phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } - } + // Not a counted loop. Keep one safepoint. + bool keep_one_sfpt = true; + remove_safepoints(phase, keep_one_sfpt); } // Recursively @@ -1906,6 +1922,15 @@ if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); } + if (_has_call) tty->print(" has_call"); + if (_has_sfpt) tty->print(" has_sfpt"); + if (_rce_candidate) tty->print(" rce"); + if (_safepts != NULL && _safepts->size() > 0) { + tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); + } + if (_required_safept != NULL && _required_safept->size() > 0) { + tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); + } tty->cr(); } @@ -2230,7 +2255,7 @@ // _nodes array holds the earliest legal controlling CFG node. // Allocate stack with enough space to avoid frequent realloc - int stack_size = (C->unique() >> 1) + 16; // (unique>>1)+16 from Java2D stats + int stack_size = (C->live_nodes() >> 1) + 16; // (live_nodes>>1)+16 from Java2D stats Node_Stack nstack( a, stack_size ); visited.Clear(); @@ -2303,6 +2328,11 @@ #endif if (skip_loop_opts) { + // restore major progress flag + for (int i = 0; i < old_progress; i++) { + C->set_major_progress(); + } + // Cleanup any modified bits _igvn.optimize(); @@ -2686,7 +2716,7 @@ } } if (_dom_stk == NULL) { - uint init_size = C->unique() / 100; // Guess that 1/100 is a reasonable initial size. + uint init_size = C->live_nodes() / 100; // Guess that 1/100 is a reasonable initial size. if (init_size < 10) init_size = 10; _dom_stk = new GrowableArray<uint>(init_size); } @@ -2776,8 +2806,8 @@ // The sort is of size number-of-control-children, which generally limits // it to size 2 (i.e., I just choose between my 2 target loops). void PhaseIdealLoop::build_loop_tree() { - // Allocate stack of size C->unique()/2 to avoid frequent realloc - GrowableArray <Node *> bltstack(C->unique() >> 1); + // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc + GrowableArray <Node *> bltstack(C->live_nodes() >> 1); Node *n = C->root(); bltstack.push(n); int pre_order = 1; @@ -3666,7 +3696,7 @@ void PhaseIdealLoop::dump( ) const { ResourceMark rm; Arena* arena = Thread::current()->resource_area(); - Node_Stack stack(arena, C->unique() >> 2); + Node_Stack stack(arena, C->live_nodes() >> 2); Node_List rpo_list; VectorSet visited(arena); visited.set(C->top()->_idx);
--- a/src/share/vm/opto/loopnode.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/loopnode.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -403,6 +403,9 @@ // encountered. void allpaths_check_safepts(VectorSet &visited, Node_List &stack); + // Remove safepoints from loop. Optionally keeping one. + void remove_safepoints(PhaseIdealLoop* phase, bool keep_one); + // Convert to counted loops where possible void counted_loop( PhaseIdealLoop *phase );
--- a/src/share/vm/opto/matcher.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/matcher.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -335,14 +335,14 @@ grow_new_node_array(C->unique()); // Reset node counter so MachNodes start with _idx at 0 - int nodes = C->unique(); // save value + int live_nodes = C->live_nodes(); C->set_unique(0); C->reset_dead_node_list(); // Recursively match trees from old space into new space. // Correct leaves of new-space Nodes; they point to old-space. _visited.Clear(); // Clear visit bits for xform call - C->set_cached_top_node(xform( C->top(), nodes )); + C->set_cached_top_node(xform( C->top(), live_nodes)); if (!C->failing()) { Node* xroot = xform( C->root(), 1 ); if (xroot == NULL) { @@ -995,7 +995,7 @@ Node *Matcher::transform( Node *n ) { ShouldNotCallThis(); return n; } Node *Matcher::xform( Node *n, int max_stack ) { // Use one stack to keep both: child's node/state and parent's node/index - MStack mstack(max_stack * 2 * 2); // C->unique() * 2 * 2 + MStack mstack(max_stack * 2 * 2); // usually: C->live_nodes() * 2 * 2 mstack.push(n, Visit, NULL, -1); // set NULL as parent to indicate root while (mstack.is_nonempty()) { @@ -2021,8 +2021,8 @@ //------------------------------find_shared------------------------------------ // Set bits if Node is shared or otherwise a root void Matcher::find_shared( Node *n ) { - // Allocate stack of size C->unique() * 2 to avoid frequent realloc - MStack mstack(C->unique() * 2); + // Allocate stack of size C->live_nodes() * 2 to avoid frequent realloc + MStack mstack(C->live_nodes() * 2); // Mark nodes as address_visited if they are inputs to an address expression VectorSet address_visited(Thread::current()->resource_area()); mstack.push(n, Visit); // Don't need to pre-visit root node
--- a/src/share/vm/opto/memnode.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/memnode.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -2370,7 +2370,7 @@ ctl != NULL, "raw memory operations should have control edge"); switch (bt) { - case T_BOOLEAN: + case T_BOOLEAN: val = gvn.transform(new (C) AndINode(val, gvn.intcon(0x1))); // Fall through to T_BYTE case case T_BYTE: return new (C) StoreBNode(ctl, mem, adr, adr_type, val, mo); case T_INT: return new (C) StoreINode(ctl, mem, adr, adr_type, val, mo); case T_CHAR:
--- a/src/share/vm/opto/node.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/node.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -329,6 +329,9 @@ // Create a Node, with a given number of required edges. Node::Node(uint req) : _idx(IDX_INIT(req)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { assert( req < Compile::current()->max_node_limit() - NodeLimitFudgeFactor, "Input limit exceeded" ); debug_only( verify_construction() ); @@ -348,6 +351,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0) : _idx(IDX_INIT(1)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -360,6 +366,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1) : _idx(IDX_INIT(2)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -374,6 +383,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2) : _idx(IDX_INIT(3)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -390,6 +402,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3) : _idx(IDX_INIT(4)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -408,6 +423,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4) : _idx(IDX_INIT(5)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -429,6 +447,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5) : _idx(IDX_INIT(6)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -452,6 +473,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5, Node *n6) : _idx(IDX_INIT(7)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -1757,7 +1781,7 @@ uint depth = (uint)ABS(d); int direction = d; Compile* C = Compile::current(); - GrowableArray <Node *> nstack(C->unique()); + GrowableArray <Node *> nstack(C->live_nodes()); nstack.append(s); int begin = 0; @@ -2091,6 +2115,17 @@ #endif } +void Node_List::dump_simple() const { +#ifndef PRODUCT + for( uint i = 0; i < _cnt; i++ ) + if( _nodes[i] ) { + tty->print(" %d", _nodes[i]->_idx); + } else { + tty->print(" NULL"); + } +#endif +} + //============================================================================= //------------------------------remove----------------------------------------- void Unique_Node_List::remove( Node *n ) {
--- a/src/share/vm/opto/node.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/node.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -294,10 +294,16 @@ public: // Each Node is assigned a unique small/dense number. This number is used - // to index into auxiliary arrays of data and bitvectors. - // It is declared const to defend against inadvertant assignment, - // since it is used by clients as a naked field. + // to index into auxiliary arrays of data and bit vectors. + // The field _idx is declared constant to defend against inadvertent assignments, + // since it is used by clients as a naked field. However, the field's value can be + // changed using the set_idx() method. + // + // The PhaseRenumberLive phase renumbers nodes based on liveness information. + // Therefore, it updates the value of the _idx field. The parse-time _idx is + // preserved in _parse_idx. const node_idx_t _idx; + DEBUG_ONLY(const node_idx_t _parse_idx;) // Get the (read-only) number of input edges uint req() const { return _cnt; } @@ -1368,6 +1374,7 @@ void clear() { _cnt = 0; Node_Array::clear(); } // retain storage uint size() const { return _cnt; } void dump() const; + void dump_simple() const; }; //------------------------------Unique_Node_List-------------------------------
--- a/src/share/vm/opto/parse1.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/parse1.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -717,6 +717,27 @@ #endif } +static Node* mask_int_value(Node* v, BasicType bt, PhaseGVN* gvn) { + Compile* C = gvn->C; + switch (bt) { + case T_BYTE: + v = gvn->transform(new (C) LShiftINode(v, gvn->intcon(24))); + v = gvn->transform(new (C) RShiftINode(v, gvn->intcon(24))); + break; + case T_SHORT: + v = gvn->transform(new (C) LShiftINode(v, gvn->intcon(16))); + v = gvn->transform(new (C) RShiftINode(v, gvn->intcon(16))); + break; + case T_CHAR: + v = gvn->transform(new (C) AndINode(v, gvn->intcon(0xFFFF))); + break; + case T_BOOLEAN: + v = gvn->transform(new (C) AndINode(v, gvn->intcon(0x1))); + break; + } + return v; +} + //-------------------------------build_exits---------------------------------- // Build normal and exceptional exit merge points. void Parse::build_exits() { @@ -741,6 +762,16 @@ // Add a return value to the exit state. (Do not push it yet.) if (tf()->range()->cnt() > TypeFunc::Parms) { const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms); + if (ret_type->isa_int()) { + BasicType ret_bt = method()->return_type()->basic_type(); + if (ret_bt == T_BOOLEAN || + ret_bt == T_CHAR || + ret_bt == T_BYTE || + ret_bt == T_SHORT) { + ret_type = TypeInt::INT; + } + } + // Don't "bind" an unloaded return klass to the ret_phi. If the klass // becomes loaded during the subsequent parsing, the loaded and unloaded // types will not join when we transform and push in do_exits(). @@ -958,6 +989,10 @@ const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms); Node* ret_phi = _gvn.transform( _exits.argument(0) ); assert(_exits.control()->is_top() || !_gvn.type(ret_phi)->empty(), "return value must be well defined"); + if (ret_type->isa_int()) { + BasicType ret_bt = method()->return_type()->basic_type(); + ret_phi = mask_int_value(ret_phi, ret_bt, &_gvn); + } _exits.push_node(ret_type->basic_type(), ret_phi); }
--- a/src/share/vm/opto/parse2.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/parse2.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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 @@ -57,11 +57,15 @@ //--------------------------------array_store---------------------------------- void Parse::array_store(BasicType elem_type) { - Node* adr = array_addressing(elem_type, 1); + const Type* elem = Type::TOP; + Node* adr = array_addressing(elem_type, 1, &elem); if (stopped()) return; // guaranteed null or range check Node* val = pop(); dec_sp(2); // Pop array and index const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(elem_type); + if (elem == TypeInt::BOOL) { + elem_type = T_BOOLEAN; + } store_to_memory(control(), adr, val, elem_type, adr_type, StoreNode::release_if_reference(elem_type)); }
--- a/src/share/vm/opto/phase.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/phase.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -67,6 +67,8 @@ elapsedTimer Phase::_t_iterGVN; elapsedTimer Phase::_t_iterGVN2; elapsedTimer Phase::_t_incrInline; +elapsedTimer Phase::_t_renumberLive; + // Subtimers for _t_registerAllocation elapsedTimer Phase::_t_ctorChaitin; @@ -115,13 +117,14 @@ } tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds()); tty->print_cr (" incrInline : %3.3f sec", Phase::_t_incrInline.seconds()); + tty->print_cr (" renumberLive : %3.3f sec", Phase::_t_renumberLive.seconds()); tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds()); tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds()); tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds()); tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds()); tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds()); tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds()); - double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + + double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + Phase::_t_renumberLive.seconds() + Phase::_t_escapeAnalysis.seconds() + Phase::_t_macroEliminate.seconds() + Phase::_t_idealLoop.seconds() + Phase::_t_ccp.seconds() + Phase::_t_macroExpand.seconds() + Phase::_t_graphReshaping.seconds();
--- a/src/share/vm/opto/phase.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/phase.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -40,22 +40,23 @@ class Phase : public StackObj { public: enum PhaseNumber { - Compiler, // Top-level compiler phase - Parser, // Parse bytecodes - Remove_Useless, // Remove useless nodes - Optimistic, // Optimistic analysis phase - GVN, // Pessimistic global value numbering phase - Ins_Select, // Instruction selection phase - CFG, // Build a CFG - BlockLayout, // Linear ordering of blocks - Register_Allocation, // Register allocation, duh - LIVE, // Dragon-book LIVE range problem - StringOpts, // StringBuilder related optimizations - Interference_Graph, // Building the IFG - Coalesce, // Coalescing copies - Ideal_Loop, // Find idealized trip-counted loops - Macro_Expand, // Expand macro nodes - Peephole, // Apply peephole optimizations + Compiler, // Top-level compiler phase + Parser, // Parse bytecodes + Remove_Useless, // Remove useless nodes + Remove_Useless_And_Renumber_Live, // First, remove useless nodes from the graph. Then, renumber live nodes. + Optimistic, // Optimistic analysis phase + GVN, // Pessimistic global value numbering phase + Ins_Select, // Instruction selection phase + CFG, // Build a CFG + BlockLayout, // Linear ordering of blocks + Register_Allocation, // Register allocation, duh + LIVE, // Dragon-book LIVE range problem + StringOpts, // StringBuilder related optimizations + Interference_Graph, // Building the IFG + Coalesce, // Coalescing copies + Ideal_Loop, // Find idealized trip-counted loops + Macro_Expand, // Expand macro nodes + Peephole, // Apply peephole optimizations last_phase }; protected: @@ -102,6 +103,7 @@ static elapsedTimer _t_iterGVN; static elapsedTimer _t_iterGVN2; static elapsedTimer _t_incrInline; + static elapsedTimer _t_renumberLive; // Subtimers for _t_registerAllocation static elapsedTimer _t_ctorChaitin;
--- a/src/share/vm/opto/phaseX.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/phaseX.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -398,7 +398,7 @@ //============================================================================= //------------------------------PhaseRemoveUseless----------------------------- // 1) Use a breadthfirst walk to collect useful nodes reachable from root. -PhaseRemoveUseless::PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ) : Phase(Remove_Useless), +PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num) : Phase(phase_num), _useful(Thread::current()->resource_area()) { // Implementation requires 'UseLoopSafepoints == true' and an edge from root @@ -435,6 +435,82 @@ } } +//============================================================================= +//------------------------------PhaseRenumberLive------------------------------ +// First, remove useless nodes (equivalent to identifying live nodes). +// Then, renumber live nodes. +// +// The set of live nodes is returned by PhaseRemoveUseless in the _useful structure. +// If the number of live nodes is 'x' (where 'x' == _useful.size()), then the +// PhaseRenumberLive updates the node ID of each node (the _idx field) with a unique +// value in the range [0, x). +// +// At the end of the PhaseRenumberLive phase, the compiler's count of unique nodes is +// updated to 'x' and the list of dead nodes is reset (as there are no dead nodes). +// +// The PhaseRenumberLive phase updates two data structures with the new node IDs. +// (1) The worklist is used by the PhaseIterGVN phase to identify nodes that must be +// processed. A new worklist (with the updated node IDs) is returned in 'new_worklist'. +// (2) Type information (the field PhaseGVN::_types) maps type information to each +// node ID. The mapping is updated to use the new node IDs as well. Updated type +// information is returned in PhaseGVN::_types. +// +// The PhaseRenumberLive phase does not preserve the order of elements in the worklist. +// +// Other data structures used by the compiler are not updated. The hash table for value +// numbering (the field PhaseGVN::_table) is not updated because computing the hash +// values is not based on node IDs. The field PhaseGVN::_nodes is not updated either +// because it is empty wherever PhaseRenumberLive is used. +PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num) : + PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live) { + + assert(RenumberLiveNodes, "RenumberLiveNodes must be set to true for node renumbering to take place"); + assert(C->live_nodes() == _useful.size(), "the number of live nodes must match the number of useful nodes"); + assert(gvn->nodes_size() == 0, "GVN must not contain any nodes at this point"); + + uint old_unique_count = C->unique(); + uint live_node_count = C->live_nodes(); + uint worklist_size = worklist->size(); + + // Storage for the updated type information. + Type_Array new_type_array(C->comp_arena()); + + // Iterate over the set of live nodes. + uint current_idx = 0; // The current new node ID. Incremented after every assignment. + for (uint i = 0; i < _useful.size(); i++) { + Node* n = _useful.at(i); + const Type* type = gvn->type_or_null(n); + new_type_array.map(current_idx, type); + + bool in_worklist = false; + if (worklist->member(n)) { + in_worklist = true; + } + + n->set_idx(current_idx); // Update node ID. + + if (in_worklist) { + new_worklist->push(n); + } + + current_idx++; + } + + assert(worklist_size == new_worklist->size(), "the new worklist must have the same size as the original worklist"); + assert(live_node_count == current_idx, "all live nodes must be processed"); + + // Replace the compiler's type information with the updated type information. + gvn->replace_types(new_type_array); + + // Update the unique node count of the compilation to the number of currently live nodes. + C->set_unique(live_node_count); + + // Set the dead node count to 0 and reset dead node list. + C->reset_dead_node_list(); +} + //============================================================================= //------------------------------PhaseTransform--------------------------------- @@ -783,7 +859,7 @@ //------------------------------PhaseIterGVN----------------------------------- // Initialize hash table to fresh and clean for +VerifyOpto PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ) : PhaseGVN(igvn,dummy), _worklist( ), - _stack(C->unique() >> 1), + _stack(C->live_nodes() >> 1), _delay_transform(false) { } @@ -800,7 +876,11 @@ // Initialize with previous PhaseGVN info from Parser PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn), _worklist(*C->for_igvn()), - _stack(C->unique() >> 1), +// TODO: Before incremental inlining it was allocated only once and it was fine. Now that +// the constructor is used in incremental inlining, this consumes too much memory: +// _stack(C->live_nodes() >> 1), +// So, as a band-aid, we replace this by: + _stack(C->comp_arena(), 32), _delay_transform(false) { uint max; @@ -1586,7 +1666,7 @@ _nodes.map( n->_idx, new_node ); // Flag as having been cloned // Allocate stack of size _nodes.Size()/2 to avoid frequent realloc - GrowableArray <Node *> trstack(C->unique() >> 1); + GrowableArray <Node *> trstack(C->live_nodes() >> 1); trstack.push(new_node); // Process children of cloned node while ( trstack.is_nonempty() ) {
--- a/src/share/vm/opto/phaseX.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/phaseX.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -148,11 +148,21 @@ Unique_Node_List _useful; // Nodes reachable from root // list is allocated from current resource area public: - PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ); + PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num = Remove_Useless); Unique_Node_List *get_useful() { return &_useful; } }; +//------------------------------PhaseRenumber---------------------------------- +// Phase that first performs a PhaseRemoveUseless, then it renumbers compiler +// structures accordingly. +class PhaseRenumberLive : public PhaseRemoveUseless { +public: + PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num = Remove_Useless_And_Renumber_Live); +}; + //------------------------------PhaseTransform--------------------------------- // Phases that analyze, then transform. Constructing the Phase object does any @@ -162,7 +172,7 @@ class PhaseTransform : public Phase { protected: Arena* _arena; - Node_Array _nodes; // Map old node indices to new nodes. + Node_List _nodes; // Map old node indices to new nodes. Type_Array _types; // Map old node indices to Types. // ConNode caches: @@ -187,7 +197,13 @@ Arena* arena() { return _arena; } Type_Array& types() { return _types; } + void replace_types(Type_Array new_types) { + _types = new_types; + } // _nodes is used in varying ways by subclasses, which define local accessors + uint nodes_size() { + return _nodes.size(); + } public: // Get a previously recorded type for the node n.
--- a/src/share/vm/opto/type.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/opto/type.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -1769,13 +1769,15 @@ break; case T_OBJECT: case T_ARRAY: + case T_FLOAT: + case T_INT: + field_array[pos++] = get_const_type(type); + break; case T_BOOLEAN: case T_CHAR: - case T_FLOAT: case T_BYTE: case T_SHORT: - case T_INT: - field_array[pos++] = get_const_type(type); + field_array[pos++] = TypeInt::INT; break; default: ShouldNotReachHere();
--- a/src/share/vm/prims/jni.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/jni.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1125,7 +1125,14 @@ protected: va_list _ap; - inline void get_bool() { _arguments->push_int(va_arg(_ap, jint)); } // bool is coerced to int when using va_arg + inline void get_bool() { + // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and + // 0 to JNI_FALSE. Boolean return values from native are normalized the same in + // TemplateInterpreterGenerator::generate_result_handler_for and + // SharedRuntime::generate_native_wrapper. + jboolean b = va_arg(_ap, jint); + _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); + } inline void get_char() { _arguments->push_int(va_arg(_ap, jint)); } // char is coerced to int when using va_arg inline void get_short() { _arguments->push_int(va_arg(_ap, jint)); } // short is coerced to int when using va_arg inline void get_byte() { _arguments->push_int(va_arg(_ap, jint)); } // byte is coerced to int when using va_arg @@ -1171,9 +1178,17 @@ while ( 1 ) { switch ( fingerprint & parameter_feature_mask ) { case bool_parm: + get_bool(); + break; case char_parm: + get_char(); + break; case short_parm: + get_short(); + break; case byte_parm: + get_byte(); + break; case int_parm: get_int(); break; @@ -1207,7 +1222,14 @@ protected: const jvalue *_ap; - inline void get_bool() { _arguments->push_int((jint)(_ap++)->z); } + inline void get_bool() { + // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and + // 0 to JNI_FALSE. Boolean return values from native are normalized the same in + // TemplateInterpreterGenerator::generate_result_handler_for and + // SharedRuntime::generate_native_wrapper. + jboolean b = (_ap++)->z; + _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); + } inline void get_char() { _arguments->push_int((jint)(_ap++)->c); } inline void get_short() { _arguments->push_int((jint)(_ap++)->s); } inline void get_byte() { _arguments->push_int((jint)(_ap++)->b); } @@ -1800,34 +1822,34 @@ // the runtime type of subword integral basic types is integer DEFINE_CALLMETHODV(jboolean, Boolean, T_BOOLEAN - , HOTSPOT_JNI_CALLBOOLEANMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBOOLEANMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBOOLEANMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBOOLEANMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jbyte, Byte, T_BYTE - , HOTSPOT_JNI_CALLBYTEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBYTEMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBYTEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBYTEMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jchar, Char, T_CHAR - , HOTSPOT_JNI_CALLCHARMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLCHARMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLCHARMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLCHARMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jshort, Short, T_SHORT - , HOTSPOT_JNI_CALLSHORTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLSHORTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLSHORTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLSHORTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jobject, Object, T_OBJECT - , HOTSPOT_JNI_CALLOBJECTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLOBJECTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLOBJECTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLOBJECTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jint, Int, T_INT, - HOTSPOT_JNI_CALLINTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLINTMETHOD_RETURN(_ret_ref)) + HOTSPOT_JNI_CALLINTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLINTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jlong, Long, T_LONG - , HOTSPOT_JNI_CALLLONGMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLLONGMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLLONGMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLLONGMETHODV_RETURN(_ret_ref)) // Float and double probes don't return value because dtrace doesn't currently support it DEFINE_CALLMETHODV(jfloat, Float, T_FLOAT - , HOTSPOT_JNI_CALLFLOATMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLFLOATMETHOD_RETURN()) + , HOTSPOT_JNI_CALLFLOATMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLFLOATMETHODV_RETURN()) DEFINE_CALLMETHODV(jdouble, Double, T_DOUBLE - , HOTSPOT_JNI_CALLDOUBLEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLDOUBLEMETHOD_RETURN()) + , HOTSPOT_JNI_CALLDOUBLEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLDOUBLEMETHODV_RETURN()) #define DEFINE_CALLMETHODA(ResultType, Result, Tag \ , EntryProbe, ReturnProbe) \ @@ -1852,34 +1874,34 @@ // the runtime type of subword integral basic types is integer DEFINE_CALLMETHODA(jboolean, Boolean, T_BOOLEAN - , HOTSPOT_JNI_CALLBOOLEANMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBOOLEANMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBOOLEANMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBOOLEANMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jbyte, Byte, T_BYTE - , HOTSPOT_JNI_CALLBYTEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBYTEMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBYTEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBYTEMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jchar, Char, T_CHAR - , HOTSPOT_JNI_CALLCHARMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLCHARMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLCHARMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLCHARMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jshort, Short, T_SHORT - , HOTSPOT_JNI_CALLSHORTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLSHORTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLSHORTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLSHORTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jobject, Object, T_OBJECT - , HOTSPOT_JNI_CALLOBJECTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLOBJECTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLOBJECTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLOBJECTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jint, Int, T_INT, - HOTSPOT_JNI_CALLINTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLINTMETHOD_RETURN(_ret_ref)) + HOTSPOT_JNI_CALLINTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLINTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jlong, Long, T_LONG - , HOTSPOT_JNI_CALLLONGMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLLONGMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLLONGMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLLONGMETHODA_RETURN(_ret_ref)) // Float and double probes don't return value because dtrace doesn't currently support it DEFINE_CALLMETHODA(jfloat, Float, T_FLOAT - , HOTSPOT_JNI_CALLFLOATMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLFLOATMETHOD_RETURN()) + , HOTSPOT_JNI_CALLFLOATMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLFLOATMETHODA_RETURN()) DEFINE_CALLMETHODA(jdouble, Double, T_DOUBLE - , HOTSPOT_JNI_CALLDOUBLEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLDOUBLEMETHOD_RETURN()) + , HOTSPOT_JNI_CALLDOUBLEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLDOUBLEMETHODA_RETURN()) DT_VOID_RETURN_MARK_DECL(CallVoidMethod, HOTSPOT_JNI_CALLVOIDMETHOD_RETURN()); DT_VOID_RETURN_MARK_DECL(CallVoidMethodV, HOTSPOT_JNI_CALLVOIDMETHODV_RETURN()); @@ -2832,6 +2854,7 @@ field_value.unionType = value; \ o = JvmtiExport::jni_SetField_probe_nh(thread, obj, o, k, fieldID, false, SigType, (jvalue *)&field_value); \ } \ + if (SigType == 'Z') { value = ((jboolean)value) & 1; } \ o->Fieldname##_field_put(offset, value); \ ReturnProbe; \ JNI_END @@ -3136,12 +3159,13 @@ field_value.unionType = value; \ JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, SigType, (jvalue *)&field_value); \ } \ + if (SigType == 'Z') { value = ((jboolean)value) & 1; } \ id->holder()->java_mirror()-> Fieldname##_field_put (id->offset(), value); \ ReturnProbe;\ JNI_END DEFINE_SETSTATICFIELD(jboolean, bool, Boolean, 'Z', z - , HOTSPOT_JNI_SETBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t)fieldID, value), + , HOTSPOT_JNI_SETSTATICBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t)fieldID, value), HOTSPOT_JNI_SETBOOLEANFIELD_RETURN()) DEFINE_SETSTATICFIELD(jbyte, byte, Byte, 'B', b , HOTSPOT_JNI_SETSTATICBYTEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value),
--- a/src/share/vm/prims/jvmtiEnvBase.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -1348,7 +1348,7 @@ ResultTypeFinder rtf(signature); TosState fr_tos = as_TosState(rtf.type()); if (fr_tos != tos) { - if (tos != itos || (fr_tos != btos && fr_tos != ctos && fr_tos != stos)) { + if (tos != itos || (fr_tos != btos && fr_tos != ztos && fr_tos != ctos && fr_tos != stos)) { return JVMTI_ERROR_TYPE_MISMATCH; } }
--- a/src/share/vm/prims/jvmtiExport.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/jvmtiExport.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -1586,7 +1586,7 @@ address location, KlassHandle field_klass, Handle object, jfieldID field, char sig_type, jvalue *value) { - if (sig_type == 'I' || sig_type == 'Z' || sig_type == 'C' || sig_type == 'S') { + if (sig_type == 'I' || sig_type == 'Z' || sig_type == 'B' || sig_type == 'C' || sig_type == 'S') { // 'I' instructions are used for byte, char, short and int. // determine which it really is, and convert fieldDescriptor fd;
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -3378,7 +3378,9 @@ // not yet in the vtable, because the vtable setup is in progress. // This must be done after we adjust the default_methods and // default_vtable_indices for methods already in the vtable. + // If redefining Unsafe, walk all the vtables looking for entries. if (ik->vtable_length() > 0 && (_the_class_oop->is_interface() + || _the_class_oop == SystemDictionary::misc_Unsafe_klass() || ik->is_subtype_of(_the_class_oop))) { // ik->vtable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); @@ -3393,7 +3395,9 @@ // interface, then we have to call adjust_method_entries() for // every InstanceKlass that has an itable since there isn't a // subclass relationship between an interface and an InstanceKlass. + // If redefining Unsafe, walk all the itables looking for entries. if (ik->itable_length() > 0 && (_the_class_oop->is_interface() + || _the_class_oop == SystemDictionary::misc_Unsafe_klass() || ik->is_subclass_of(_the_class_oop))) { // ik->itable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); @@ -3751,7 +3755,7 @@ // Deoptimize all activations depending on marked nmethods Deoptimization::deoptimize_dependents(); - // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies) + // Make the dependent methods not entrant CodeCache::make_marked_nmethods_not_entrant(); // From now on we know that the dependency information is complete
--- a/src/share/vm/prims/unsafe.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/unsafe.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. 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 @@ -156,13 +156,22 @@ ///// Data in the Java heap. +#define truncate_jboolean(x) ((x) & 1) +#define truncate_jbyte(x) (x) +#define truncate_jshort(x) (x) +#define truncate_jchar(x) (x) +#define truncate_jint(x) (x) +#define truncate_jlong(x) (x) +#define truncate_jfloat(x) (x) +#define truncate_jdouble(x) (x) + #define GET_FIELD(obj, offset, type_name, v) \ oop p = JNIHandles::resolve(obj); \ type_name v = *(type_name*)index_oop_from_field_offset_long(p, offset) #define SET_FIELD(obj, offset, type_name, x) \ oop p = JNIHandles::resolve(obj); \ - *(type_name*)index_oop_from_field_offset_long(p, offset) = x + *(type_name*)index_oop_from_field_offset_long(p, offset) = truncate_##type_name(x) #define GET_FIELD_VOLATILE(obj, offset, type_name, v) \ oop p = JNIHandles::resolve(obj); \ @@ -173,7 +182,7 @@ #define SET_FIELD_VOLATILE(obj, offset, type_name, x) \ oop p = JNIHandles::resolve(obj); \ - OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x); + OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), truncate_##type_name(x)); // Macros for oops that check UseCompressedOops
--- a/src/share/vm/prims/whitebox.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/prims/whitebox.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -45,6 +45,7 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/g1/concurrentMark.hpp" +#include "gc_implementation/g1/concurrentMarkThread.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #endif // INCLUDE_ALL_GCS @@ -323,8 +324,16 @@ WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); - ConcurrentMark* cm = g1->concurrent_mark(); - return cm->concurrent_marking_in_progress(); + return g1->concurrent_mark()->cmThread()->during_cycle(); +WB_END + +WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o)) + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + if (!g1h->concurrent_mark()->cmThread()->during_cycle()) { + g1h->collect(GCCause::_wb_conc_mark); + return true; + } + return false; WB_END WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) @@ -1031,6 +1040,7 @@ {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, + {CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle }, {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;", (void*)&WB_G1AuxiliaryMemoryUsage }, #endif // INCLUDE_ALL_GCS
--- a/src/share/vm/runtime/arguments.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/arguments.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -3444,7 +3444,7 @@ } if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path("[classpath: ", _java_class_path->value()); + ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); } }
--- a/src/share/vm/runtime/deoptimization.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -905,13 +905,25 @@ break; } - case T_SHORT: case T_CHAR: // 2 bytes + case T_SHORT: assert(value->type() == T_INT, "Agreement."); val = value->get_int(); obj->short_at_put(index, (jshort)*((jint*)&val)); break; - case T_BOOLEAN: case T_BYTE: // 1 byte + case T_CHAR: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->char_field_put(index, (jchar)*((jint*)&val)); + break; + + case T_BYTE: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->byte_field_put(index, (jbyte)*((jint*)&val)); + break; + + case T_BOOLEAN: assert(value->type() == T_INT, "Agreement."); val = value->get_int(); obj->bool_at_put(index, (jboolean)*((jint*)&val)); @@ -1026,17 +1038,29 @@ break; } - case T_SHORT: case T_CHAR: // 2 bytes - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->short_field_put(offset, (jshort)*((jint*)&val)); - break; + case T_SHORT: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->short_field_put(offset, (jshort)*((jint*)&val)); + break; + + case T_CHAR: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->char_field_put(offset, (jchar)*((jint*)&val)); + break; - case T_BOOLEAN: case T_BYTE: // 1 byte - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->bool_field_put(offset, (jboolean)*((jint*)&val)); - break; + case T_BYTE: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->byte_field_put(offset, (jbyte)*((jint*)&val)); + break; + + case T_BOOLEAN: + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->bool_field_put(offset, (jboolean)*((jint*)&val)); + break; default: ShouldNotReachHere();
--- a/src/share/vm/runtime/globals.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/globals.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -1303,6 +1303,13 @@ "Decay time (in milliseconds) to re-enable bulk rebiasing of a " \ "type after previous bulk rebias") \ \ + product(bool, ExitOnOutOfMemoryError, false, \ + "JVM exits on the first occurrence of an out-of-memory error") \ + \ + product(bool, CrashOnOutOfMemoryError, false, \ + "JVM aborts, producing an error log and core/mini dump, on the " \ + "first occurrence of an out-of-memory error") \ + \ /* tracing */ \ \ notproduct(bool, TraceRuntimeCalls, false, \
--- a/src/share/vm/runtime/objectMonitor.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/objectMonitor.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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 @@ -226,7 +226,8 @@ // // * The monitor entry list operations avoid locks, but strictly speaking // they're not lock-free. Enter is lock-free, exit is not. -// See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html +// For a description of 'Methods and apparatus providing non-blocking access +// to a resource,' see U.S. Pat. No. 7844973. // // * The cxq can have multiple concurrent "pushers" but only one concurrent // detaching thread. This mechanism is immune from the ABA corruption. @@ -1955,7 +1956,8 @@ // (duration) or we can fix the count at approximately the duration of // a context switch and vary the frequency. Of course we could also // vary both satisfying K == Frequency * Duration, where K is adaptive by monitor. -// See http://j2se.east/~dice/PERSIST/040824-AdaptiveSpinning.html. +// For a description of 'Adaptive spin-then-block mutual exclusion in +// multi-threaded processing,' see U.S. Pat. No. 8046758. // // This implementation varies the duration "D", where D varies with // the success rate of recent spin attempts. (D is capped at approximately
--- a/src/share/vm/runtime/reflection.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/reflection.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -1101,7 +1101,7 @@ void Reflection::narrow(jvalue* value, BasicType narrow_type, TRAPS) { switch (narrow_type) { case T_BOOLEAN: - value->z = (jboolean) value->i; + value->z = (jboolean) (value->i & 1); return; case T_BYTE: value->b = (jbyte) value->i;
--- a/src/share/vm/runtime/safepoint.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/safepoint.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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 @@ -739,80 +739,12 @@ // ------------------------------------------------------------------------------------------------------ // Exception handlers -#ifndef PRODUCT - -#ifdef SPARC - -#ifdef _LP64 -#define PTR_PAD "" -#else -#define PTR_PAD " " -#endif - -static void print_ptrs(intptr_t oldptr, intptr_t newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR_FORMAT PTR_PAD " %s %c " PTR_FORMAT PTR_PAD " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_longs(jlong oldptr, jlong newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR64_FORMAT " %s %c " PTR64_FORMAT " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_me(intptr_t *new_sp, intptr_t *old_sp, bool *was_oops) { -#ifdef _LP64 - tty->print_cr("--------+------address-----+------before-----------+-------after----------+"); - const int incr = 1; // Increment to skip a long, in units of intptr_t -#else - tty->print_cr("--------+--address-+------before-----------+-------after----------+"); - const int incr = 2; // Increment to skip a long, in units of intptr_t -#endif - tty->print_cr("---SP---|"); - for( int i=0; i<16; i++ ) { - tty->print("blob %c%d |"PTR_FORMAT" ","LO"[i>>3],i&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print_cr("--------|"); - for( int i1=0; i1<frame::memory_parameter_word_sp_offset-16; i1++ ) { - tty->print("argv pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print(" pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); - tty->print_cr("--------|"); - tty->print(" G1 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G3 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G4 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G5 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print_cr(" FSR |"PTR_FORMAT" "PTR64_FORMAT" "PTR64_FORMAT,new_sp,*(jlong*)old_sp,*(jlong*)new_sp); - old_sp += incr; new_sp += incr; was_oops += incr; - // Skip the floats - tty->print_cr("--Float-|"PTR_FORMAT,new_sp); - tty->print_cr("---FP---|"); - old_sp += incr*32; new_sp += incr*32; was_oops += incr*32; - for( int i2=0; i2<16; i2++ ) { - tty->print("call %c%d |"PTR_FORMAT" ","LI"[i2>>3],i2&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->cr(); -} -#endif // SPARC -#endif // PRODUCT - void SafepointSynchronize::handle_polling_page_exception(JavaThread *thread) { assert(thread->is_Java_thread(), "polling reference encountered by VM thread"); assert(thread->thread_state() == _thread_in_Java, "should come from Java code"); assert(SafepointSynchronize::is_synchronizing(), "polling encountered outside safepoint synchronization"); - // Uncomment this to get some serious before/after printing of the - // Sparc safepoint-blob frame structure. - /* - intptr_t* sp = thread->last_Java_sp(); - intptr_t stack_copy[150]; - for( int i=0; i<150; i++ ) stack_copy[i] = sp[i]; - bool was_oops[150]; - for( int i=0; i<150; i++ ) - was_oops[i] = stack_copy[i] ? ((oop)stack_copy[i])->is_oop() : false; - */ - if (ShowSafepointMsgs) { tty->print("handle_polling_page_exception: "); } @@ -824,7 +756,6 @@ ThreadSafepointState* state = thread->safepoint_state(); state->handle_polling_page_exception(); - // print_me(sp,stack_copy,was_oops); }
--- a/src/share/vm/runtime/sweeper.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/sweeper.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -546,10 +546,14 @@ } else if (nm->is_not_entrant()) { // If there are no current activations of this method on the // stack we can safely convert it to a zombie method - if (nm->can_not_entrant_be_converted()) { + if (nm->can_convert_to_zombie()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } + // Clear ICStubs to prevent back patching stubs of zombie or unloaded + // nmethods during the next safepoint (see ICStub::finalize). + MutexLocker cl(CompiledIC_lock); + nm->clear_ic_stubs(); // Code cache state change is tracked in make_zombie() nm->make_zombie(); _zombified_count++; @@ -575,6 +579,12 @@ release_nmethod(nm); _flushed_count++; } else { + { + // Clean ICs of unloaded nmethods as well because they may reference other + // unloaded nmethods that may be flushed earlier in the sweeper cycle. + MutexLocker cl(CompiledIC_lock); + nm->cleanup_inline_caches(); + } // Code cache state change is tracked in make_zombie() nm->make_zombie(); _zombified_count++;
--- a/src/share/vm/runtime/synchronizer.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/synchronizer.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -121,7 +121,7 @@ } \ } -#define HOTSPOT_MONITOR_PROBE_waited HOTSPOT_MONITOR_PROBE_WAITED +#define HOTSPOT_MONITOR_PROBE_waited HOTSPOT_MONITOR_WAITED #define DTRACE_MONITOR_PROBE(probe, monitor, obj, thread) \ { \
--- a/src/share/vm/runtime/thread.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/thread.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -145,8 +145,8 @@ #else /* USDT2 */ -#define HOTSPOT_THREAD_PROBE_start HOTSPOT_THREAD_PROBE_START -#define HOTSPOT_THREAD_PROBE_stop HOTSPOT_THREAD_PROBE_STOP +#define HOTSPOT_THREAD_PROBE_start HOTSPOT_THREAD_START +#define HOTSPOT_THREAD_PROBE_stop HOTSPOT_THREAD_STOP #define DTRACE_THREAD_PROBE(probe, javathread) \ { \
--- a/src/share/vm/runtime/threadLocalStorage.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/threadLocalStorage.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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 @@ -38,6 +38,11 @@ # include "os_bsd.inline.hpp" #endif +// Solaris no longer has this kind of ThreadLocalStorage implementation. +// This will be removed from all platforms in the near future. + +#ifndef SOLARIS + // static member initialization int ThreadLocalStorage::_thread_index = -1; @@ -65,3 +70,5 @@ bool ThreadLocalStorage::is_initialized() { return (thread_index() != -1); } + +#endif // SOLARIS
--- a/src/share/vm/runtime/threadLocalStorage.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/threadLocalStorage.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -38,10 +38,14 @@ extern "C" uintptr_t _raw_thread_id(); class ThreadLocalStorage : AllStatic { + + // Exported API public: static void set_thread(Thread* thread); static Thread* get_thread_slow(); static void invalidate_all() { pd_invalidate_all(); } + static void init(); + static bool is_initialized(); // Machine dependent stuff #ifdef TARGET_OS_ARCH_linux_x86 @@ -78,17 +82,12 @@ # include "threadLS_bsd_zero.hpp" #endif - +#ifndef SOLARIS public: // Accessor static inline int thread_index() { return _thread_index; } static inline void set_thread_index(int index) { _thread_index = index; } - // Initialization - // Called explicitly from VMThread::activate_system instead of init_globals. - static void init(); - static bool is_initialized(); - private: static int _thread_index; @@ -97,6 +96,9 @@ // Processor dependent parts of set_thread and initialization static void pd_set_thread(Thread* thread); static void pd_init(); + +#endif // SOLARIS + // Invalidate any thread cacheing or optimization schemes. static void pd_invalidate_all();
--- a/src/share/vm/runtime/vm_operations.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/runtime/vm_operations.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -106,8 +106,8 @@ // Deoptimize all activations depending on marked nmethods Deoptimization::deoptimize_dependents(); - // Make the dependent methods zombies - CodeCache::make_marked_nmethods_zombies(); + // Make the dependent methods not entrant + CodeCache::make_marked_nmethods_not_entrant(); }
--- a/src/share/vm/services/management.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/services/management.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1107,6 +1107,8 @@ bool with_locked_monitors, bool with_locked_synchronizers, TRAPS) { + // no need to actually perform thread dump if no TIDs are specified + if (num_threads == 0) return; // First get an array of threadObj handles. // A JavaThread may terminate before we get the stack trace.
--- a/src/share/vm/utilities/debug.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/utilities/debug.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -302,6 +302,16 @@ VMError err(message); err.report_java_out_of_memory(); } + + if (CrashOnOutOfMemoryError) { + tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message); + fatal(err_msg("OutOfMemory encountered: %s", message)); + } + + if (ExitOnOutOfMemoryError) { + tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message); + exit(3); + } } }
--- a/src/share/vm/utilities/globalDefinitions.hpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/utilities/globalDefinitions.hpp Wed Jun 01 00:11:44 2016 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -796,14 +796,15 @@ enum TosState { // describes the tos cache contents btos = 0, // byte, bool tos cached - ctos = 1, // char tos cached - stos = 2, // short tos cached - itos = 3, // int tos cached - ltos = 4, // long tos cached - ftos = 5, // float tos cached - dtos = 6, // double tos cached - atos = 7, // object cached - vtos = 8, // tos not cached + ztos = 1, // byte, bool tos cached + ctos = 2, // char tos cached + stos = 3, // short tos cached + itos = 4, // int tos cached + ltos = 5, // long tos cached + ftos = 6, // float tos cached + dtos = 7, // double tos cached + atos = 8, // object cached + vtos = 9, // tos not cached number_of_states, ilgl // illegal state: should not occur }; @@ -812,7 +813,7 @@ inline TosState as_TosState(BasicType type) { switch (type) { case T_BYTE : return btos; - case T_BOOLEAN: return btos; // FIXME: Add ztos + case T_BOOLEAN: return ztos; case T_CHAR : return ctos; case T_SHORT : return stos; case T_INT : return itos; @@ -828,8 +829,8 @@ inline BasicType as_BasicType(TosState state) { switch (state) { - //case ztos: return T_BOOLEAN;//FIXME case btos : return T_BYTE; + case ztos : return T_BOOLEAN; case ctos : return T_CHAR; case stos : return T_SHORT; case itos : return T_INT;
--- a/src/share/vm/utilities/vmError.cpp Tue May 31 08:05:44 2016 +0200 +++ b/src/share/vm/utilities/vmError.cpp Wed Jun 01 00:11:44 2016 +0200 @@ -230,7 +230,7 @@ if (signame) { jio_snprintf(buf, buflen, - "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" UINTX_FORMAT, + "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" INTPTR_FORMAT, signame, _id, _pc, os::current_process_id(), os::current_thread_id()); } else if (_filename != NULL && _lineno > 0) { @@ -238,7 +238,7 @@ char separator = os::file_separator()[0]; const char *p = strrchr(_filename, separator); int n = jio_snprintf(buf, buflen, - "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT, + "Internal Error at %s:%d, pid=%d, tid=" INTPTR_FORMAT, p ? p + 1 : _filename, _lineno, os::current_process_id(), os::current_thread_id()); if (n >= 0 && n < buflen && _message) { @@ -252,7 +252,7 @@ } } else { jio_snprintf(buf, buflen, - "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT, + "Internal Error (0x%x), pid=%d, tid=" INTPTR_FORMAT, _id, os::current_process_id(), os::current_thread_id()); } @@ -439,7 +439,7 @@ // process id, thread id st->print(", pid=%d", os::current_process_id()); - st->print(", tid=" UINTX_FORMAT, os::current_thread_id()); + st->print(", tid=" INTPTR_FORMAT, os::current_thread_id()); st->cr(); STEP(40, "(printing error message)")
--- a/test/TEST.groups Tue May 31 08:05:44 2016 +0200 +++ b/test/TEST.groups Wed Jun 01 00:11:44 2016 +0200 @@ -96,7 +96,8 @@ runtime/Thread/TestThreadDumpMonitorContention.java \ runtime/XCheckJniJsig/XCheckJSig.java \ serviceability/attach/AttachWithStalePidFile.java \ - serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java + serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \ + testlibrary_tests/ # JRE adds further tests to compact3 @@ -251,7 +252,6 @@ serviceability/ \ compiler/ \ testlibrary/ \ - testlibrary_tests/ \ sanity/ \ runtime/ \ gc/ \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/escapeAnalysis/TestEABadMergeMem.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 8134031 + * @summary Bad rewiring of memory edges when we split unique types during EA + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestEABadMergeMem::m_notinlined TestEABadMergeMem + * + */ + +public class TestEABadMergeMem { + + static class Box { + int i; + } + + static void m_notinlined() { + } + + static float dummy1; + static float dummy2; + + static int test(Box a, Box c, int i, int j, int k, boolean flag1, boolean flag2) { + Box b = new Box(); // non escaping + a.i = i; + b.i = j; + c.i = k; + + m_notinlined(); + + boolean flag3 = false; + if (flag1) { + for (int ii = 0; ii < 100; ii++) { + if (flag2) { + dummy1 = (float)ii; + } else { + dummy2 = (float)ii; + } + } + flag3 = true; + } + // Memory Phi here with projection of not inlined call as one edge, MergeMem as other + + if (flag3) { // will split through Phi during loopopts + int res = c.i + b.i; + m_notinlined(); // prevents split through phi during igvn + return res; + } else { + return 44 + 43; + } + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + // m(2); + Box a = new Box(); + Box c = new Box(); + int res = test(a, c, 42, 43, 44, (i%2) == 0, (i%3) == 0); + if (res != 44 + 43) { + throw new RuntimeException("Bad result " + res); + } + } + } + +}
--- a/test/compiler/loopopts/CountedLoopProblem.java Tue May 31 08:05:44 2016 +0200 +++ b/test/compiler/loopopts/CountedLoopProblem.java Wed Jun 01 00:11:44 2016 +0200 @@ -36,18 +36,22 @@ public static void main(String[] args) throws Exception { Random r = new Random(42); int x = 0; - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < 1000000; ++i) { - int v = Math.abs(r.nextInt()); - sb.append('+').append(v).append('\n'); - x += v; - // To trigger the problem we must OSR in the following loop - // To make the problem 100% reproducible run with -XX:-TieredCompilation -XX:OSROnlyBCI=62 - while(x < 0) x += 1000000000; - sb.append('=').append(x).append('\n'); - } - if (sb.toString().hashCode() != 0xaba94591) { - throw new Exception("Unexpected result"); + try { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 1000000; ++i) { + int v = Math.abs(r.nextInt()); + sb.append('+').append(v).append('\n'); + x += v; + // To trigger the problem we must OSR in the following loop + // To make the problem 100% reproducible run with -XX:-TieredCompilation -XX:OSROnlyBCI=62 + while(x < 0) x += 1000000000; + sb.append('=').append(x).append('\n'); + } + if (sb.toString().hashCode() != 0xaba94591) { + throw new Exception("Unexpected result"); + } + } catch(OutOfMemoryError e) { + // small heap, ignore } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/UseCountedLoopSafepoints.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 6869327 + * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop + * @library /testlibrary + * @run main UseCountedLoopSafepoints + */ + +import java.util.concurrent.atomic.AtomicLong; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class UseCountedLoopSafepoints { + private static final AtomicLong _num = new AtomicLong(0); + + // Uses the fact that an EnableBiasedLocking vmop will be started + // after 500ms, while we are still in the loop. If there is a + // safepoint in the counted loop, then we will reach safepoint + // very quickly. Otherwise SafepointTimeout will be hit. + public static void main (String args[]) throws Exception { + if (args.length == 1) { + final int loops = Integer.parseInt(args[0]); + for (int i = 0; i < loops; i++) { + _num.addAndGet(1); + } + } else { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", + "-XX:+UseBiasedLocking", + "-XX:BiasedLockingStartupDelay=500", + "-XX:+SafepointTimeout", + "-XX:SafepointTimeoutDelay=2000", + "-XX:+UseCountedLoopSafepoints", + "UseCountedLoopSafepoints", + "2000000000" + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Timeout detected"); + output.shouldHaveExitValue(0); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/native/TestDirtyInt.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. + */ + +public class TestDirtyInt { + static { + System.loadLibrary("TestDirtyInt"); + } + + native static int test(int v); + + static int compiled(int v) { + return test(v<<2); + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + int res = compiled(Integer.MAX_VALUE); + if (res != 0x42) { + throw new RuntimeException("Test failed"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/native/TestDirtyInt.sh Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,80 @@ +#!/bin/sh + +# +# Copyright (c) 2016, Oracle and/or its affiliates. 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 8148353 +## @summary gcc on sparc expects clean 32 bit int in 64 bit register on function entry +## @run shell/timeout=30 TestDirtyInt.sh +## + +if [ "${TESTSRC}" = "" ] +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" +fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh + +# set platform-dependent variables +if [ $VM_OS == "linux" -a $VM_CPU == "sparcv9" ]; then + echo "Testing on linux-sparc" + gcc_cmd=`which gcc` + if [ "x$gcc_cmd" == "x" ]; then + echo "WARNING: gcc not found. Cannot execute test." 2>&1 + exit 0; + fi +else + echo "Test passed; only valid for linux-sparc" + exit 0; +fi + +THIS_DIR=. + +cp ${TESTSRC}${FS}*.java ${THIS_DIR} +${TESTJAVA}${FS}bin${FS}javac *.java + +$gcc_cmd -O1 -DLINUX -fPIC -shared \ + -o ${TESTSRC}${FS}libTestDirtyInt.so \ + -I${TESTJAVA}${FS}include \ + -I${TESTJAVA}${FS}include${FS}linux \ + ${TESTSRC}${FS}libTestDirtyInt.c + +# run the java test in the background +cmd="${TESTJAVA}${FS}bin${FS}java \ + -Djava.library.path=${TESTSRC}${FS} TestDirtyInt" + +echo "$cmd" +eval $cmd + +if [ $? = 0 ] +then + echo "Test Passed" + exit 0 +fi + +echo "Test Failed" +exit 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/native/libTestDirtyInt.c Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. + */ + +#include "jni.h" +#include <stdio.h> + +static int array = 0x42; + +JNIEXPORT jint JNICALL Java_TestDirtyInt_test(JNIEnv* env, jclass jclazz, jint v) +{ + int* ptr = &array + v + 4; + return *ptr; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestSoftReferencesBehaviorOnOOME.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014 Oracle and/or its affiliates. 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 TestSoftReferencesBehaviorOnOOME + * @key gc + * @summary Tests that all SoftReferences has been cleared at time of OOM. + * @library /testlibrary + * @build TestSoftReferencesBehaviorOnOOME + * @run main/othervm -Xmx128m TestSoftReferencesBehaviorOnOOME 512 2k + * @run main/othervm -Xmx128m TestSoftReferencesBehaviorOnOOME 128k 256k + * @run main/othervm -Xmx128m TestSoftReferencesBehaviorOnOOME 2k 32k 10 + */ +import java.util.*; +import com.oracle.java.testlibrary.Utils; +import java.lang.ref.SoftReference; +import java.util.LinkedList; + +public class TestSoftReferencesBehaviorOnOOME { + + private static final Random rndGenerator = new Random(); + + public static void main(String[] args) { + int semiRefAllocFrequency = DEFAULT_FREQUENCY; + long minSize = DEFAULT_MIN_SIZE, + maxSize = DEFAULT_MAX_SIZE; + + if ( args.length >= 3 ) { + semiRefAllocFrequency = Integer.parseInt(args[2]); + } + + if ( args.length >= 2) { + maxSize = getBytesCount(args[1]); + } + + if ( args.length >= 1) { + minSize = getBytesCount(args[0]); + } + + new TestSoftReferencesBehaviorOnOOME().softReferencesOom(minSize, maxSize, semiRefAllocFrequency); + } + + /** + * Test that all SoftReferences has been cleared at time of OOM. + */ + void softReferencesOom(long minSize, long maxSize, int semiRefAllocFrequency) { + System.out.format( "minSize = %d, maxSize = %d, freq = %d%n", minSize, maxSize, semiRefAllocFrequency ); + long counter = 0; + + long multiplier = maxSize - minSize; + LinkedList<SoftReference> arrSoftRefs = new LinkedList(); + LinkedList arrObjects = new LinkedList(); + long numberOfNotNulledObjects = 0; + long oomSoftArraySize = 0; + + try { + while (true) { + // Keep every Xth object to make sure we hit OOM pretty fast + if (counter % semiRefAllocFrequency != 0) { + long allocationSize = ((int) (rndGenerator.nextDouble() * multiplier)) + + minSize; + arrObjects.add(new byte[(int)allocationSize]); + } else { + arrSoftRefs.add(new SoftReference(new Object())); + } + + counter++; + if (counter == Long.MAX_VALUE) { + counter = 0; + } + } + } catch (OutOfMemoryError oome) { + // Clear allocated ballast, so we don't get another OOM. + + arrObjects = null; + + // Get the number of soft refs first, so we don't trigger + // another OOM. + oomSoftArraySize = arrSoftRefs.size(); + + for (SoftReference sr : arrSoftRefs) { + Object o = sr.get(); + + if (o != null) { + numberOfNotNulledObjects++; + } + } + + // Make sure we clear all refs before we return failure + arrSoftRefs = null; + + if (numberOfNotNulledObjects > 0) { + throw new RuntimeException(numberOfNotNulledObjects + " out of " + + oomSoftArraySize + " SoftReferences was not " + + "null at time of OutOfMemoryError"); + } + } finally { + arrSoftRefs = null; + arrObjects = null; + } + } + + private static final long getBytesCount(String arg) { + String postfixes = "kMGT"; + long mod = 1; + + if (arg.trim().length() >= 2) { + mod = postfixes.indexOf( + arg.trim().charAt(arg.length() - 1) + ); + + if (mod != -1) { + mod = (long) Math.pow(1024, mod+1); + arg = arg.substring(0, arg.length() - 1); + } else { + mod = 1; // 10^0 + } + } + + return Long.parseLong(arg) * mod; + } + + private static final long DEFAULT_MIN_SIZE = 512; + private static final long DEFAULT_MAX_SIZE = 1024; + private static final int DEFAULT_FREQUENCY = 4; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/whitebox/TestConcMarkCycleWB.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. 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 TestConMarkCycleWB + * @bug 8065579 + * @requires vm.gc=="null" | vm.gc=="G1" + * @library /testlibrary /testlibrary/whitebox + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.WhiteBox TestConcMarkCycleWB + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC TestConcMarkCycleWB + * @summary Verifies that ConcurrentMarking-related WB works properly + */ +import static com.oracle.java.testlibrary.Asserts.assertFalse; +import static com.oracle.java.testlibrary.Asserts.assertTrue; +import sun.hotspot.WhiteBox; + +public class TestConcMarkCycleWB { + + public static void main(String[] args) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + + wb.youngGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + + wb.fullGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + assertTrue(wb.g1StartConcMarkCycle()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc_implementation/g1/TestNoEagerReclaimOfHumongousRegions.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 TestNoEagerReclaimOfHumongousRegions + * @bug 8139424 + * @summary Test to check that a live humongous object is not eagerly reclaimed. This is a regression test for + * 8139424 and the test will crash if an eager reclaim occur. The test is not 100% deterministic and + * might pass even if there are problems in the code, but it will never crash unless there is a problem. + * @requires vm.gc=="G1" | vm.gc=="null" + * @key gc + * @library /testlibrary /testlibrary/whitebox + * @modules java.base/sun.misc + * @build TestNoEagerReclaimOfHumongousRegions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+PrintGC -XX:+UseG1GC -XX:MaxTenuringThreshold=0 -XX:G1RSetSparseRegionEntries=32 -XX:G1HeapRegionSize=1m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+G1TraceEagerReclaimHumongousObjects TestNoEagerReclaimOfHumongousRegions + */ + +import java.util.LinkedList; + +import sun.hotspot.WhiteBox; + +public class TestNoEagerReclaimOfHumongousRegions { + // Helper class to keep reference to humongous byte[]. + static class LargeRef { + private byte[] _ref; + + LargeRef(byte[] ref) { + _ref = ref; + } + + byte[] ref() { return _ref; } + } + + static LargeRef humongous_reference_holder; + + public static void main(String[] args) throws InterruptedException{ + WhiteBox wb = WhiteBox.getWhiteBox(); + LinkedList<Object> garbageAndRefList = new LinkedList<Object>(); + // Creating a 1M large byte array. Since the test specifies the heap + // region size to be 1m this will be a humongous object. We then + // store a pointer to the array in the static object to keep it live + // during the whole test. + humongous_reference_holder = new LargeRef(new byte[1 * 1024 * 1024]); + + // Create some garbage and a reference to the humongous object each round. + for (int i = 0; i < 32; i++) { + garbageAndRefList.add(new byte[400*1000]); + garbageAndRefList.add(new LargeRef(humongous_reference_holder.ref())); + + // Promote to old, goal is to get rem-set entries for the humongous + // object from different regions. The test specifies MaxTenuringThreshold=0, + // this will make sure we get objects promoted to old at once. + wb.youngGC(); + } + // Clear the garbage and reference list. + garbageAndRefList.clear(); + + // Run a concurrent mark cycle to mark all references but the static one as dead. + wb.g1StartConcMarkCycle(); + while (wb.g1InConcurrentMark()) { + Thread.sleep(100); + } + + // Run a young collection to make sure humongous object still can't be eagerly reclaimed. + wb.youngGC(); + // Will crash/assert if humongous object has been reclaimed. + wb.fullGC(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 TestCrashOnOutOfMemoryError + * @summary Test using -XX:+CrashOnOutOfMemoryError + * @library /testlibrary + * @build jdk.test.lib.* + * @run driver TestCrashOnOutOfMemoryError + * @bug 8138745 + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +public class TestCrashOnOutOfMemoryError { + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't abort JVM!"); + } + } + // else this is the main test + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", + "-Xmx64m", TestCrashOnOutOfMemoryError.class.getName(),"throwOOME"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + int exitValue = output.getExitValue(); + if (0 == exitValue) { + //expecting a non zero value + throw new Error("Expected to get non zero exit value"); + } + + /* Output should look something like this. The actual text will depend on the OS and its core dump processing. + Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit + # To suppress the following error report, specify this argument + # after -XX: or in .hotspotrc: SuppressErrorAt=/debug.cpp:303 + # + # A fatal error has been detected by the Java Runtime Environment: + # + # Internal Error (/home/cheleswer/Desktop/jdk9/dev/hotspot/src/share/vm/utilities/debug.cpp:303), pid=6212, tid=6213 + # fatal error: OutOfMemory encountered: Requested array size exceeds VM limit + # + # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00) + # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64) + # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to + /home/cheleswer/Desktop/core.6212) + # + # An error report file with more information is saved as: + # /home/cheleswer/Desktop/hs_err_pid6212.log + # + # If you would like to submit a bug report, please visit: + # http://bugreport.java.com/bugreport/crash.jsp + # + Current thread is 6213 + Dumping core ... + Aborted (core dumped) + */ + output.shouldContain("Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit"); + // extract hs-err file + String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); + if (hs_err_file == null) { + throw new Error("Did not find hs-err file in output.\n"); + } + + /* + * Check if hs_err files exist or not + */ + File f = new File(hs_err_file); + if (!f.exists()) { + throw new Error("hs-err file missing at "+ f.getAbsolutePath() + ".\n"); + } + + System.out.println("PASSED"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestExitOnOutOfMemoryError.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 TestExitOnOutOfMemoryError + * @summary Test using -XX:ExitOnOutOfMemoryError + * @library /testlibrary + * @build jdk.test.lib.* + * @run driver TestExitOnOutOfMemoryError + * @bug 8138745 + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestExitOnOutOfMemoryError { + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't terminate JVM!"); + } + } + + // else this is the main test + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+ExitOnOutOfMemoryError", + "-Xmx64m", TestExitOnOutOfMemoryError.class.getName(), "throwOOME"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + /* + * Actual output should look like this: + * Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit + */ + output.shouldHaveExitValue(3); + output.shouldContain("Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit"); + System.out.println("PASSED"); + } +}
--- a/test/runtime/NMT/JcmdWithNMTDisabled.java Tue May 31 08:05:44 2016 +0200 +++ b/test/runtime/NMT/JcmdWithNMTDisabled.java Wed Jun 01 00:11:44 2016 +0200 @@ -26,10 +26,7 @@ * @key nmt jcmd * @summary Verify that jcmd correctly reports that NMT is not enabled * @library /testlibrary - * First run without enabling NMT - * @run main/othervm JcmdWithNMTDisabled - * Then run with explicitly disabling NMT, should not be any difference - * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + * @run main JcmdWithNMTDisabled 1 */ import com.oracle.java.testlibrary.*; @@ -39,6 +36,27 @@ static String pid; public static void main(String args[]) throws Exception { + + // This test explicitly needs to be run with the exact command lines below, not passing on + // arguments from the parent VM is a conscious choice to avoid NMT being turned on. + if (args.length > 0) { + ProcessBuilder pb; + OutputAnalyzer output; + String testjdkPath = System.getProperty("test.jdk"); + + // First run without enabling NMT + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + // Then run with explicitly disabling NMT, should not be any difference + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + return; + } + // Grab my own PID pid = Integer.toString(ProcessTools.getProcessId());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/stress/gc/TestStressRSetCoarsening.java Wed Jun 01 00:11:44 2016 +0200 @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. + */ + +import java.util.concurrent.TimeoutException; +import sun.hotspot.WhiteBox; + +/* + * @test TestStressRSetCoarsening.java + * @key stress + * @bug 8146984 8147087 + * @requires vm.gc=="G1" | vm.gc=="null" + * @requires os.maxMemory > 3G + * + * @summary Stress G1 Remembered Set by creating a lot of cross region links + * @library /testlibrary /testlibrary/whitebox + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=300 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 0 300 + * @run main/othervm/timeout=300 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 10 300 + * @run main/othervm/timeout=300 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 42 10 300 + * @run main/othervm/timeout=300 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 2 0 300 + * @run main/othervm/timeout=1800 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 500 0 1800 + * @run main/othervm/timeout=1800 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc + * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 10 10 1800 + */ + +/** + * What the test does. + * Preparation stage: + * Fill out ~90% of the heap with objects, each object is an object array. + * If we want to allocate K objects per region, we calculate N to meet: + * sizeOf(Object[N]) ~= regionSize / K + * Stress stage: + * No more allocation, so no more GC. + * We will perform a number of iterations. On each iteration i, + * for each pair of regions Rx and Ry we will set c[i] references + * from Rx to Ry. If c[i] less than c[i-1] at the end of iteration + * concurrent mark cycle will be initiated (to recalculate remembered sets). + * As the result RSet will be growing up and down, up and down many times. + * + * The test expects: no crash and no timeouts. + * + * Test Parameters: + * args[0] - number of objects per Heap Region (1 - means humongous) + * args[1] - number of regions to refresh to provoke GC at the end of cycle. + * (0 - means no GC, i.e. no reading from RSet) + * args[2] - timeout in seconds (to stop execution to avoid jtreg timeout) + */ +public class TestStressRSetCoarsening { + + public static void main(String... args) throws InterruptedException { + if (args.length != 3) { + throw new IllegalArgumentException("Wrong number of arguments " + args.length); + } + int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous + int regsToRefresh = Integer.parseInt(args[1]); // 0 means no regions to refresh at the end of cycle + int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler + new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go(); + } + + private static final long KB = 1024; + private static final long MB = 1024 * KB; + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public final Object[][] storage; + + /** + * Number of objects per region. This is a test parameter. + */ + public final int K; + + /** + * Length of object array: sizeOf(Object[N]) ~= regionSize / K + * N will be calculated as function of K. + */ + public final int N; + + /** + * How many regions involved into testing. + * Will be calculated as heapFractionToAllocate * freeRegionCount. + */ + public final int regionCount; + + /** + * How much heap to use. + */ + public final float heapFractionToAllocate = 0.9f; + + /** + * How many regions to be refreshed at the end of cycle. + * This is a test parameter. + */ + public final int regsToRefresh; + + /** + * Initial time. + */ + public final long start; + + /** + * Time when the test should stop working. + */ + public final long finishAt; + + /** + * Does pre-calculation and allocate necessary objects. + * + * @param objPerRegions how many objects per G1 heap region + */ + TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) { + this.K = objPerRegions; + this.regsToRefresh = regsToRefresh; + this.start = System.currentTimeMillis(); + this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout + + long regionSize = WB.g1RegionSize(); + + // How many free regions + Runtime rt = Runtime.getRuntime(); + long used = rt.totalMemory() - rt.freeMemory(); + long totalFree = rt.maxMemory() - used; + regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate); + long toAllocate = regionCount * regionSize; + System.out.println("%% Test parameters"); + System.out.println("%% Objects per region : " + K); + System.out.println("%% Heap fraction to allocate : " + (int) (heapFractionToAllocate * 100) + "%"); + System.out.println("%% Regions to refresh to provoke GC: " + regsToRefresh); + + System.out.println("%% Memory"); + System.out.println("%% used : " + used / MB + "M"); + System.out.println("%% available : " + totalFree / MB + "M"); + System.out.println("%% to allocate : " + toAllocate / MB + "M"); + System.out.println("%% (in regs) : " + regionCount); + System.out.println("%% G1 Region Size: " + regionSize / MB + "M"); + + int refSize = WB.getHeapOopSize(); + + // Calculate N: K*sizeOf(Object[N]) ~= regionSize + // sizeOf(Object[N]) ~= (N+4)*refSize + // ==> + // N = regionSize / K / refSize - 4; + N = (int) ((regionSize / K) / refSize) - 5; + + /* + * -------------- + * region0 storage[0] = new Object[N] + * ... + * storage[K-1] = new Object[N] + * --------------- + * region1 storage[K] = new Object[N] + * ... + * storage[2*K - 1] = new Object[N] + * -------------- + * ... + * -------------- + * regionX storage[X*K] = new Object[N] + * ... + * storage[(X+1)*K -1] = new Object[N] + * where X = HeapFraction * TotalRegions + * ------------- + */ + System.out.println("%% Objects"); + System.out.println("%% N (array length) : " + N); + System.out.println("%% K (objects in regions): " + K); + System.out.println("%% Reference size : " + refSize); + System.out.println("%% Approximate obj size : " + (N + 2) * refSize / KB + "K)"); + + storage = new Object[regionCount * K][]; + for (int i = 0; i < storage.length; i++) { + storage[i] = new Object[N]; + } + } + + public void go() throws InterruptedException { + // threshold for sparce -> fine + final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue(); + + // threshold for fine -> coarse + final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue(); + + // regToRegRefCounts - array of reference counts from region to region + // at the the end of iteration. + // The number of test iterations is array length - 1. + // If c[i] > c[i-1] then during the iteration i more references will + // be created. + // If c[i] < c[i-1] then some referenes will be cleaned. + int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0, + COARSE, COARSE + 10, FINE + 1, FINE / 2, 0}; + + // For progress tracking + int[] progress = new int[regToRegRefCounts.length]; + progress[0] = 0; + for (int i = 1; i < regToRegRefCounts.length; i++) { + progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]); + } + try { + for (int i = 1; i < regToRegRefCounts.length; i++) { + int pre = regToRegRefCounts[i - 1]; + int cur = regToRegRefCounts[i]; + float prog = ((float) progress[i - 1] / progress[progress.length - 1]); + + System.out.println("%% step " + i + + " out of " + (regToRegRefCounts.length - 1) + + " (~" + (int) (100 * prog) + "% done)"); + System.out.println("%% " + pre + " --> " + cur); + for (int to = 0; to < regionCount; to++) { + // Select a celebrity object that we will install references to. + // The celebrity will be referred from all other regions. + // If the number of references after should be less than they + // were before, select NULL. + Object celebrity = cur > pre ? storage[to * K] : null; + for (int from = 0; from < regionCount; from++) { + if (to == from) { + continue; // no need to refer to itself + } + + int step = cur > pre ? +1 : -1; + for (int rn = pre; rn != cur; rn += step) { + storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity; + if (System.currentTimeMillis() > finishAt) { + throw new TimeoutException(); + } + } + } + } + if (pre > cur) { + // Number of references went down. + // Need to provoke recalculation of RSet. + WB.g1StartConcMarkCycle(); + while (WB.g1InConcurrentMark()) { + Thread.sleep(1); + } + } + + // To force the use of rememebered set entries we need to provoke a GC. + // To induce some fragmentation, and some mixed GCs, we need + // to make a few objects unreachable. + for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) { + int to = toClean % regionCount; + // Need to remove all references from all regions to the region 'to' + for (int from = 0; from < regionCount; from++) { + if (to == from) { + continue; // no need to refer to itself + } + for (int rn = 0; rn <= cur; rn++) { + storage[getY(to, from, rn)][getX(to, from, rn)] = null; + } + } + // 'Refresh' storage elements for the region 'to' + // After that loop all 'old' objects in the region 'to' + // should become unreachable. + for (int k = 0; k < K; k++) { + storage[(to * K + k) % storage.length] = new Object[N]; + } + } + } + } catch (TimeoutException e) { + System.out.println("%% TIMEOUT!!!"); + } + long now = System.currentTimeMillis(); + System.out.println("%% Summary"); + System.out.println("%% Time spent : " + ((now - start) / 1000) + " seconds"); + System.out.println("%% Free memory left : " + Runtime.getRuntime().freeMemory() / KB + "K"); + System.out.println("%% Test passed"); + } + + /** + * Returns X index in the Storage of the reference #rn from the region + * 'from' to the region 'to'. + * + * @param to region # to refer to + * @param from region # to refer from + * @param rn number of reference + * + * @return X index in the range: [0 ... N-1] + */ + private int getX(int to, int from, int rn) { + return (rn * regionCount + to) % N; + } + + /** + * Returns Y index in the Storage of the reference #rn from the region + * 'from' to the region 'to'. + * + * @param to region # to refer to + * @param from region # to refer from + * @param rn number of reference + * + * @return Y index in the range: [0 ... K*regionCount -1] + */ + private int getY(int to, int from, int rn) { + return ((rn * regionCount + to) / N + from * K) % (regionCount * K); + } +} +
--- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Tue May 31 08:05:44 2016 +0200 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Wed Jun 01 00:11:44 2016 +0200 @@ -74,11 +74,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void shouldContain(String expectedString) { + public OutputAnalyzer shouldContain(String expectedString) { if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); } + return this; } /** @@ -87,11 +88,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void stdoutShouldContain(String expectedString) { + public OutputAnalyzer stdoutShouldContain(String expectedString) { if (!stdout.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); } + return this; } /** @@ -100,11 +102,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void stderrShouldContain(String expectedString) { + public OutputAnalyzer stderrShouldContain(String expectedString) { if (!stderr.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); } + return this; } /** @@ -113,7 +116,7 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void shouldNotContain(String notExpectedString) { + public OutputAnalyzer shouldNotContain(String notExpectedString) { if (stdout.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); @@ -122,6 +125,7 @@ reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); } + return this; } /** @@ -130,11 +134,12 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void stdoutShouldNotContain(String notExpectedString) { + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { if (stdout.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); } + return this; } /** @@ -143,11 +148,12 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void stderrShouldNotContain(String notExpectedString) { + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { if (stderr.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); } + return this; } /** @@ -157,7 +163,7 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void shouldMatch(String pattern) { + public OutputAnalyzer shouldMatch(String pattern) { Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (!stdoutMatcher.find() && !stderrMatcher.find()) { @@ -165,6 +171,7 @@ throw new RuntimeException("'" + pattern + "' missing from stdout/stderr \n"); } + return this; } /** @@ -174,13 +181,14 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void stdoutShouldMatch(String pattern) { + public OutputAnalyzer stdoutShouldMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (!matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' missing from stdout \n"); } + return this; } /** @@ -190,13 +198,14 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void stderrShouldMatch(String pattern) { + public OutputAnalyzer stderrShouldMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (!matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' missing from stderr \n"); } + return this; } /** @@ -206,7 +215,7 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void shouldNotMatch(String pattern) { + public OutputAnalyzer shouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (matcher.find()) { reportDiagnosticSummary(); @@ -219,6 +228,7 @@ throw new RuntimeException("'" + pattern + "' found in stderr: '" + matcher.group() + "' \n"); } + return this; } /** @@ -228,13 +238,14 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void stdoutShouldNotMatch(String pattern) { + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' found in stdout \n"); } + return this; } /** @@ -244,13 +255,14 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void stderrShouldNotMatch(String pattern) { + public OutputAnalyzer stderrShouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' found in stderr \n"); } + return this; } /** @@ -290,12 +302,13 @@ * @param expectedExitValue Expected exit value from process * @throws RuntimeException If the exit value from the process did not match the expected value */ - public void shouldHaveExitValue(int expectedExitValue) { + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { if (getExitValue() != expectedExitValue) { reportDiagnosticSummary(); throw new RuntimeException("Expected to get exit value of [" + expectedExitValue + "]\n"); } + return this; }
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue May 31 08:05:44 2016 +0200 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Wed Jun 01 00:11:44 2016 +0200 @@ -174,12 +174,16 @@ public native long incMetaspaceCapacityUntilGC(long increment); public native long metaspaceCapacityUntilGC(); - // force Young GC + // Force Young GC public native void youngGC(); - // force Full GC + // Force Full GC public native void fullGC(); + // Method tries to start concurrent mark cycle. + // It returns false if CM Thread is always in concurrent cycle. + public native boolean g1StartConcMarkCycle(); + // Tests on ReservedSpace/VirtualSpace classes public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); public native void runMemoryUnitTests();