Mercurial > hg > icedtea8-forest > hotspot
changeset 10803:c8c10298f00a
Merge jdk8u272-ga
line wrap: on
line diff
--- a/.hgtags Tue Oct 27 03:35:20 2020 +0000 +++ b/.hgtags Tue Oct 27 06:33:36 2020 +0000 @@ -1409,3 +1409,11 @@ 414c1dcfc3f3620b73cc7faf23f9a3ffde83b240 jdk8u272-b02 e649f213636810823e761473ac871ce55a5235f7 jdk8u272-b03 9cc00eb32cbd7a2081ebf67a778ab2137fafc3d1 icedtea-3.17.0pre02 +cbabffce5685f9a18bfd05bd1fb18c4c73be98cf jdk8u272-b04 +1b2d99958c293b7ab324c5786664f82c8e9c4e50 jdk8u272-b05 +4b0aa85a95653f44cc45f2ec0571153017ebbf03 jdk8u272-b06 +4689eaf1a5c9c5e284d466631420761f4bd4ecae jdk8u272-b07 +a0eb08e2db5a40956a9c2d6b7dea76a894559033 jdk8u272-b08 +176a7e5cc0609cface769e5e8a31b00700d223ba jdk8u272-b09 +6b836efa38fef1b50ba798b6e344ab44ee995812 jdk8u272-b10 +6b836efa38fef1b50ba798b6e344ab44ee995812 jdk8u272-ga
--- a/THIRD_PARTY_README Tue Oct 27 03:35:20 2020 +0000 +++ b/THIRD_PARTY_README Tue Oct 27 06:33:36 2020 +0000 @@ -2240,7 +2240,7 @@ ------------------------------------------------------------------------------- -%% This notice is provided with respect to PC/SC Lite v1.8.24, +%% This notice is provided with respect to PC/SC Lite v1.8.26, which may be included with JRE 8, JDK 8, and OpenJDK 8 on Linux and Solaris. --- begin of LICENSE --- @@ -3241,3 +3241,42 @@ --- end of LICENSE --- ------------------------------------------------------------------------------- + +%% This notice is provided with respect to OASIS PKCS #11 Cryptographic Token +Interface v2.40, which may be included with JRE 8, JDK 8, and OpenJDK 8. + +--- begin of LICENSE --- + +Copyright (c) OASIS Open 2016. All Rights Reserved. + +All capitalized terms in the following text have the meanings assigned to them +in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The +full Policy may be found at the OASIS website: +[http://www.oasis-open.org/policies-guidelines/ipr] + +This document and translations of it may be copied and furnished to others, and +derivative works that comment on or otherwise explain it or assist in its +implementation may be prepared, copied, published, and distributed, in whole or +in part, without restriction of any kind, provided that the above copyright +notice and this section are included on all such copies and derivative works. +However, this document itself may not be modified in any way, including by +removing the copyright notice or references to OASIS, except as needed for the +purpose of developing any document or deliverable produced by an OASIS +Technical Committee (in which case the rules applicable to copyrights, as set +forth in the OASIS IPR Policy, must be followed) or as required to translate it +into languages other than English. + +The limited permissions granted above are perpetual and will not be revoked by +OASIS or its successors or assigns. + +This document and the information contained herein is provided on an "AS IS" +basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT +INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR +FITNESS FOR A PARTICULAR PURPOSE. OASIS AND ITS MEMBERS WILL NOT BE LIABLE FOR +ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE +OF THIS DOCUMENT OR ANY PART THEREOF. + +--- end of LICENSE --- + +-------------------------------------------------------------------------------
--- a/make/excludeSrc.make Tue Oct 27 03:35:20 2020 +0000 +++ b/make/excludeSrc.make Tue Oct 27 06:33:36 2020 +0000 @@ -95,6 +95,7 @@ gc_shared_keep := \ adaptiveSizePolicy.cpp \ ageTable.cpp \ + ageTableTracer.cpp \ collectorCounters.cpp \ cSpaceCounters.cpp \ gcId.cpp \
--- a/make/linux/makefiles/mapfile-vers-debug Tue Oct 27 03:35:20 2020 +0000 +++ b/make/linux/makefiles/mapfile-vers-debug Tue Oct 27 06:33:36 2020 +0000 @@ -190,6 +190,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsUseContainerSupport; JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen;
--- a/make/linux/makefiles/mapfile-vers-product Tue Oct 27 03:35:20 2020 +0000 +++ b/make/linux/makefiles/mapfile-vers-product Tue Oct 27 06:33:36 2020 +0000 @@ -185,6 +185,7 @@ JVM_IsInterface; JVM_IsInterrupted; JVM_IsNaN; + JVM_IsUseContainerSupport; JVM_IsPrimitiveClass; JVM_IsSameClassPackage; JVM_IsSilentCompiler;
--- a/src/share/vm/classfile/altHashing.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/altHashing.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, 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 @@ -22,12 +22,29 @@ * */ +/* + * halfsiphash code adapted from reference implementation + * (https://github.com/veorq/SipHash/blob/master/halfsiphash.c) + * which is distributed with the following copyright: + * + * SipHash reference C implementation + * + * Copyright (c) 2016 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com> + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + #include "precompiled.hpp" #include "classfile/altHashing.hpp" -#include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "oops/markOop.hpp" -#include "runtime/thread.hpp" +#include "runtime/os.hpp" // Get the hash code of the classes mirror if it exists, otherwise just // return a random number, which is one of the possible hash code used for @@ -39,266 +56,292 @@ } // Seed value used for each alternative hash calculated. -juint AltHashing::compute_seed() { - jlong nanos = os::javaTimeNanos(); - jlong now = os::javaTimeMillis(); - int SEED_MATERIAL[8] = { - (int) object_hash(SystemDictionary::String_klass()), - (int) object_hash(SystemDictionary::System_klass()), - (int) os::random(), // current thread isn't a java thread - (int) (((julong)nanos) >> 32), - (int) nanos, - (int) (((julong)now) >> 32), - (int) now, - (int) (os::javaTimeNanos() >> 2) +uint64_t AltHashing::compute_seed() { + uint64_t nanos = os::javaTimeNanos(); + uint64_t now = os::javaTimeMillis(); + uint32_t SEED_MATERIAL[8] = { + (uint32_t) object_hash(SystemDictionary::String_klass()), + (uint32_t) object_hash(SystemDictionary::System_klass()), + (uint32_t) os::random(), // current thread isn't a java thread + (uint32_t) (((uint64_t)nanos) >> 32), + (uint32_t) nanos, + (uint32_t) (((uint64_t)now) >> 32), + (uint32_t) now, + (uint32_t) (os::javaTimeNanos() >> 2) }; - return murmur3_32(SEED_MATERIAL, 8); + return halfsiphash_64(SEED_MATERIAL, 8); +} + +// utility function copied from java/lang/Integer +static uint32_t Integer_rotateLeft(uint32_t i, int distance) { + return (i << distance) | (i >> (32 - distance)); +} + +static void halfsiphash_rounds(uint32_t v[4], int rounds) { + while (rounds-- > 0) { + v[0] += v[1]; + v[1] = Integer_rotateLeft(v[1], 5); + v[1] ^= v[0]; + v[0] = Integer_rotateLeft(v[0], 16); + v[2] += v[3]; + v[3] = Integer_rotateLeft(v[3], 8); + v[3] ^= v[2]; + v[0] += v[3]; + v[3] = Integer_rotateLeft(v[3], 7); + v[3] ^= v[0]; + v[2] += v[1]; + v[1] = Integer_rotateLeft(v[1], 13); + v[1] ^= v[2]; + v[2] = Integer_rotateLeft(v[2], 16); + } + } + +static void halfsiphash_adddata(uint32_t v[4], uint32_t newdata, int rounds) { + v[3] ^= newdata; + halfsiphash_rounds(v, rounds); + v[0] ^= newdata; } +static void halfsiphash_init32(uint32_t v[4], uint64_t seed) { + v[0] = seed & 0xffffffff; + v[1] = seed >> 32; + v[2] = 0x6c796765 ^ v[0]; + v[3] = 0x74656462 ^ v[1]; +} -// Murmur3 hashing for Symbol -juint AltHashing::murmur3_32(juint seed, const jbyte* data, int len) { - juint h1 = seed; +static void halfsiphash_init64(uint32_t v[4], uint64_t seed) { + halfsiphash_init32(v, seed); + v[1] ^= 0xee; +} + +uint32_t halfsiphash_finish32(uint32_t v[4], int rounds) { + v[2] ^= 0xff; + halfsiphash_rounds(v, rounds); + return (v[1] ^ v[3]); +} + +static uint64_t halfsiphash_finish64(uint32_t v[4], int rounds) { + uint64_t rv; + v[2] ^= 0xee; + halfsiphash_rounds(v, rounds); + rv = v[1] ^ v[3]; + v[1] ^= 0xdd; + halfsiphash_rounds(v, rounds); + rv |= (uint64_t)(v[1] ^ v[3]) << 32; + return rv; +} + +// HalfSipHash-2-4 (32-bit output) for Symbols +uint32_t AltHashing::halfsiphash_32(uint64_t seed, const uint8_t* data, int len) { + uint32_t v[4]; + uint32_t newdata; + int off = 0; int count = len; - int offset = 0; + halfsiphash_init32(v, seed); // body while (count >= 4) { - juint k1 = (data[offset] & 0x0FF) - | (data[offset + 1] & 0x0FF) << 8 - | (data[offset + 2] & 0x0FF) << 16 - | data[offset + 3] << 24; + // Avoid sign extension with 0x0ff + newdata = (data[off] & 0x0FF) + | (data[off + 1] & 0x0FF) << 8 + | (data[off + 2] & 0x0FF) << 16 + | data[off + 3] << 24; count -= 4; - offset += 4; + off += 4; - k1 *= 0xcc9e2d51; - k1 = Integer_rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer_rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; + halfsiphash_adddata(v, newdata, 2); } // tail + newdata = ((uint32_t)len) << 24; // (Byte.SIZE / Byte.SIZE); if (count > 0) { - juint k1 = 0; - switch (count) { case 3: - k1 ^= (data[offset + 2] & 0xff) << 16; + newdata |= (data[off + 2] & 0x0ff) << 16; // fall through case 2: - k1 ^= (data[offset + 1] & 0xff) << 8; + newdata |= (data[off + 1] & 0x0ff) << 8; // fall through case 1: - k1 ^= (data[offset] & 0xff); + newdata |= (data[off] & 0x0ff); // fall through - default: - k1 *= 0xcc9e2d51; - k1 = Integer_rotateLeft(k1, 15); - k1 *= 0x1b873593; - h1 ^= k1; } } - // finalization - h1 ^= len; + halfsiphash_adddata(v, newdata, 2); - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - return h1; + // finalization + return halfsiphash_finish32(v, 4); } -// Murmur3 hashing for Strings -juint AltHashing::murmur3_32(juint seed, const jchar* data, int len) { - juint h1 = seed; - +// HalfSipHash-2-4 (32-bit output) for Strings +uint32_t AltHashing::halfsiphash_32(uint64_t seed, const uint16_t* data, int len) { + uint32_t v[4]; + uint32_t newdata; int off = 0; int count = len; + halfsiphash_init32(v, seed); + // body while (count >= 2) { - jchar d1 = data[off++] & 0xFFFF; - jchar d2 = data[off++]; - juint k1 = (d1 | d2 << 16); + uint16_t d1 = data[off++] & 0x0FFFF; + uint16_t d2 = data[off++]; + newdata = (d1 | d2 << 16); count -= 2; - k1 *= 0xcc9e2d51; - k1 = Integer_rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer_rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; + halfsiphash_adddata(v, newdata, 2); } // tail - + newdata = ((uint32_t)len * 2) << 24; // (Character.SIZE / Byte.SIZE); if (count > 0) { - juint k1 = (juint)data[off]; - - k1 *= 0xcc9e2d51; - k1 = Integer_rotateLeft(k1, 15); - k1 *= 0x1b873593; - h1 ^= k1; + newdata |= (uint32_t)data[off]; } + halfsiphash_adddata(v, newdata, 2); // finalization - h1 ^= len * 2; // (Character.SIZE / Byte.SIZE); - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - return h1; + return halfsiphash_finish32(v, 4); } -// Hash used for the seed. -juint AltHashing::murmur3_32(juint seed, const int* data, int len) { - juint h1 = seed; +// HalfSipHash-2-4 (64-bit output) for integers (used to create seed) +uint64_t AltHashing::halfsiphash_64(uint64_t seed, const uint32_t* data, int len) { + uint32_t v[4]; int off = 0; int end = len; + halfsiphash_init64(v, seed); + // body while (off < end) { - juint k1 = (juint)data[off++]; - - k1 *= 0xcc9e2d51; - k1 = Integer_rotateLeft(k1, 15); - k1 *= 0x1b873593; - - h1 ^= k1; - h1 = Integer_rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; + halfsiphash_adddata(v, (uint32_t)data[off++], 2); } // tail (always empty, as body is always 32-bit chunks) // finalization - - h1 ^= len * 4; // (Integer.SIZE / Byte.SIZE); - - // finalization mix force all bits of a hash block to avalanche - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - return h1; + halfsiphash_adddata(v, ((uint32_t)len * 4) << 24, 2); // (Integer.SIZE / Byte.SIZE); + return halfsiphash_finish64(v, 4); } -juint AltHashing::murmur3_32(const int* data, int len) { - return murmur3_32(0, data, len); +// HalfSipHash-2-4 (64-bit output) for integers (used to create seed) +uint64_t AltHashing::halfsiphash_64(const uint32_t* data, int len) { + return halfsiphash_64((uint64_t)0, data, len); } #ifndef PRODUCT -// Overloaded versions for internal test. -juint AltHashing::murmur3_32(const jbyte* data, int len) { - return murmur3_32(0, data, len); -} + void AltHashing::testHalfsiphash_32_ByteArray() { + const int factor = 4; -juint AltHashing::murmur3_32(const jchar* data, int len) { - return murmur3_32(0, data, len); -} + uint8_t vector[256]; + uint8_t hashes[factor * 256]; + + for (int i = 0; i < 256; i++) { + vector[i] = (uint8_t) i; + } -// Internal test for alternate hashing. Translated from JDK version -// test/sun/misc/Hashing.java -static const jbyte ONE_BYTE[] = { (jbyte) 0x80}; -static const jbyte TWO_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81}; -static const jchar ONE_CHAR[] = { (jchar) 0x8180}; -static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82}; -static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83}; -static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382}; -static const jint ONE_INT[] = { (jint) 0x83828180}; -static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85}; -static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584}; -static const jbyte EIGHT_BYTE[] = { - (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, - (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85, - (jbyte) 0x86, (jbyte) 0x87}; -static const jchar FOUR_CHAR[] = { - (jchar) 0x8180, (jchar) 0x8382, - (jchar) 0x8584, (jchar) 0x8786}; + // Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255} + for (int i = 0; i < 256; i++) { + uint32_t hash = AltHashing::halfsiphash_32(256 - i, vector, i); + hashes[i * factor] = (uint8_t) hash; + hashes[i * factor + 1] = (uint8_t)(hash >> 8); + hashes[i * factor + 2] = (uint8_t)(hash >> 16); + hashes[i * factor + 3] = (uint8_t)(hash >> 24); + } + + // hash to get const result. + uint32_t final_hash = AltHashing::halfsiphash_32(0, hashes, factor*256); -static const jint TWO_INT[] = { (jint) 0x83828180, (jint) 0x87868584}; - -static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3; + // Value found using reference implementation for the hashes array. + //uint64_t k = 0; // seed + //uint32_t reference; + //halfsiphash((const uint8_t*)hashes, factor*256, (const uint8_t *)&k, (uint8_t*)&reference, 4); + //printf("0x%x", reference); -void AltHashing::testMurmur3_32_ByteArray() { - // printf("testMurmur3_32_ByteArray\n"); + static const uint32_t HALFSIPHASH_32_BYTE_CHECK_VALUE = 0xd2be7fd8; - jbyte vector[256]; - jbyte hashes[4 * 256]; - - for (int i = 0; i < 256; i++) { - vector[i] = (jbyte) i; + assert (HALFSIPHASH_32_BYTE_CHECK_VALUE == final_hash, + err_msg( + "Calculated hash result not as expected. Expected " UINT32_FORMAT " got " UINT32_FORMAT, + HALFSIPHASH_32_BYTE_CHECK_VALUE, + final_hash)); } - // Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255} - for (int i = 0; i < 256; i++) { - juint hash = murmur3_32(256 - i, vector, i); - hashes[i * 4] = (jbyte) hash; - hashes[i * 4 + 1] = (jbyte)(hash >> 8); - hashes[i * 4 + 2] = (jbyte)(hash >> 16); - hashes[i * 4 + 3] = (jbyte)(hash >> 24); + void AltHashing::testHalfsiphash_32_CharArray() { + const int factor = 2; + + uint16_t vector[256]; + uint16_t hashes[factor * 256]; + + for (int i = 0; i < 256; i++) { + vector[i] = (uint16_t) i; + } + + // Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255} + for (int i = 0; i < 256; i++) { + uint32_t hash = AltHashing::halfsiphash_32(256 - i, vector, i); + hashes[i * factor] = (uint16_t) hash; + hashes[i * factor + 1] = (uint16_t)(hash >> 16); + } + + // hash to get const result. + uint32_t final_hash = AltHashing::halfsiphash_32(0, hashes, factor*256); + + // Value found using reference implementation for the hashes array. + //uint64_t k = 0; // seed + //uint32_t reference; + //halfsiphash((const uint8_t*)hashes, 2*factor*256, (const uint8_t *)&k, (uint8_t*)&reference, 4); + //printf("0x%x", reference); + + static const uint32_t HALFSIPHASH_32_CHAR_CHECK_VALUE = 0x428bf8a5; + + assert(HALFSIPHASH_32_CHAR_CHECK_VALUE == final_hash, + err_msg( + "Calculated hash result not as expected. Expected " UINT32_FORMAT " got " UINT32_FORMAT, + HALFSIPHASH_32_CHAR_CHECK_VALUE, + final_hash)); } - // hash to get const result. - juint final_hash = murmur3_32(hashes, 4*256); - - assert (MURMUR3_32_X86_CHECK_VALUE == final_hash, - err_msg( - "Calculated hash result not as expected. Expected %08X got %08X\n", - MURMUR3_32_X86_CHECK_VALUE, - final_hash)); -} + // Test against sample hashes published with the reference implementation: + // https://github.com/veorq/SipHash + void AltHashing::testHalfsiphash_64_FromReference() { -void AltHashing::testEquivalentHashes() { - juint jbytes, jchars, ints; - - // printf("testEquivalentHashes\n"); - - jbytes = murmur3_32(TWO_BYTE, 2); - jchars = murmur3_32(ONE_CHAR, 1); - assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + const uint64_t seed = 0x0706050403020100; + const uint64_t results[16] = { + 0xc83cb8b9591f8d21, 0xa12ee55b178ae7d5, + 0x8c85e4bc20e8feed, 0x99c7f5ae9f1fc77b, + 0xb5f37b5fd2aa3673, 0xdba7ee6f0a2bf51b, + 0xf1a63fae45107470, 0xb516001efb5f922d, + 0x6c6211d8469d7028, 0xdc7642ec407ad686, + 0x4caec8671cc8385b, 0x5ab1dc27adf3301e, + 0x3e3ea94bc0a8eaa9, 0xe150f598795a4402, + 0x1d5ff142f992a4a1, 0x60e426bf902876d6 + }; + uint32_t vector[16]; - jbytes = murmur3_32(FOUR_BYTE, 4); - jchars = murmur3_32(TWO_CHAR, 2); - ints = murmur3_32(ONE_INT, 1); - assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); - - jbytes = murmur3_32(SIX_BYTE, 6); - jchars = murmur3_32(THREE_CHAR, 3); - assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + for (int i = 0; i < 16; i++) + vector[i] = 0x03020100 + i * 0x04040404; - jbytes = murmur3_32(EIGHT_BYTE, 8); - jchars = murmur3_32(FOUR_CHAR, 4); - ints = murmur3_32(TWO_INT, 2); - assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); -} + for (int i = 0; i < 16; i++) { + uint64_t hash = AltHashing::halfsiphash_64(seed, vector, i); + assert(results[i] == hash, + err_msg( + "Calculated hash result not as expected. Round %d: " + "Expected " UINT64_FORMAT_X " got " UINT64_FORMAT_X "\n", + i, + results[i], + hash)); + } + } -// Returns true if the alternate hashcode is correct void AltHashing::test_alt_hash() { - testMurmur3_32_ByteArray(); - testEquivalentHashes(); + testHalfsiphash_32_ByteArray(); + testHalfsiphash_32_CharArray(); + testHalfsiphash_64_FromReference(); } #endif // PRODUCT
--- a/src/share/vm/classfile/altHashing.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/altHashing.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -26,37 +26,30 @@ #define SHARE_VM_CLASSFILE_ALTHASHING_HPP #include "prims/jni.h" -#include "classfile/symbolTable.hpp" +#include "memory/allocation.hpp" /** - * Hashing utilities. - * - * Implementation of Murmur3 hashing. - * This code was translated from src/share/classes/sun/misc/Hashing.java - * code in the JDK. + * Implementation of alternate more secure hashing. */ class AltHashing : AllStatic { - // utility function copied from java/lang/Integer - static juint Integer_rotateLeft(juint i, int distance) { - return (i << distance) | (i >> (32-distance)); - } - static juint murmur3_32(const int* data, int len); - static juint murmur3_32(juint seed, const int* data, int len); + // For the seed computation + static uint64_t halfsiphash_64(const uint32_t* data, int len); + static uint64_t halfsiphash_64(uint64_t seed, const uint32_t* data, int len); + #ifndef PRODUCT + // Hashing functions used for internal testing + static void testHalfsiphash_32_ByteArray(); + static void testHalfsiphash_32_CharArray(); + static void testHalfsiphash_64_FromReference(); + #endif // PRODUCT + public: + static uint64_t compute_seed(); -#ifndef PRODUCT - // Hashing functions used for internal testing - static juint murmur3_32(const jbyte* data, int len); - static juint murmur3_32(const jchar* data, int len); - static void testMurmur3_32_ByteArray(); - static void testEquivalentHashes(); -#endif // PRODUCT - - public: - static juint compute_seed(); - static juint murmur3_32(juint seed, const jbyte* data, int len); - static juint murmur3_32(juint seed, const jchar* data, int len); + // For Symbols + static uint32_t halfsiphash_32(uint64_t seed, const uint8_t* data, int len); + // For Strings + static uint32_t halfsiphash_32(uint64_t seed, const uint16_t* data, int len); NOT_PRODUCT(static void test_alt_hash();) }; #endif // SHARE_VM_CLASSFILE_ALTHASHING_HPP
--- a/src/share/vm/classfile/classFileParser.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -2691,8 +2691,83 @@ // Inner classes can be static, private or protected (classic VM does this) #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) +// Find index of the InnerClasses entry for the specified inner_class_info_index. +// Return -1 if none is found. +static int inner_classes_find_index(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) { + Symbol* cp_klass_name = cp->klass_name_at(inner); + for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) { + int idx_inner = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset); + if (cp->klass_name_at(idx_inner) == cp_klass_name) { + return idx; + } + } + return -1; +} + +// Return the outer_class_info_index for the InnerClasses entry containing the +// specified inner_class_info_index. Return -1 if no InnerClasses entry is found. +static int inner_classes_jump_to_outer(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) { + if (inner == 0) return -1; + int idx = inner_classes_find_index(inner_classes, inner, cp, length); + if (idx == -1) return -1; + int result = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset); + return result; +} + +// Return true if circularity is found, false if no circularity is found. +// Use Floyd's cycle finding algorithm. +static bool inner_classes_check_loop_through_outer(const Array<u2>* inner_classes, int idx, const ConstantPool* cp, int length) { + int slow = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset); + int fast = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset); + while (fast != -1 && fast != 0) { + if (slow != 0 && (cp->klass_name_at(slow) == cp->klass_name_at(fast))) { + return true; // found a circularity + } + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); + if (fast == -1) return false; + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); + if (fast == -1) return false; + slow = inner_classes_jump_to_outer(inner_classes, slow, cp, length); + assert(slow != -1, "sanity check"); + } + return false; +} + +// Loop through each InnerClasses entry checking for circularities and duplications +// with other entries. If duplicate entries are found then throw CFE. Otherwise, +// return true if a circularity or entries with duplicate inner_class_info_indexes +// are found. +bool ClassFileParser::check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS) { + // Loop through each InnerClasses entry. + for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) { + // Return true if there are circular entries. + if (inner_classes_check_loop_through_outer(_inner_classes, idx, cp, length)) { + return true; + } + // Check if there are duplicate entries or entries with the same inner_class_info_index. + for (int y = idx + InstanceKlass::inner_class_next_offset; y < length; + y += InstanceKlass::inner_class_next_offset) { + + // To maintain compatibility, throw an exception if duplicate inner classes + // entries are found. + guarantee_property((_inner_classes->at(idx) != _inner_classes->at(y) || + _inner_classes->at(idx+1) != _inner_classes->at(y+1) || + _inner_classes->at(idx+2) != _inner_classes->at(y+2) || + _inner_classes->at(idx+3) != _inner_classes->at(y+3)), + "Duplicate entry in InnerClasses attribute in class file %s", + CHECK_(true)); + // Return true if there are two entries with the same inner_class_info_index. + if (_inner_classes->at(y) == _inner_classes->at(idx)) { + return true; + } + } + } + return false; +} + // Return number of classes in the inner classes attribute table -u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, +u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ConstantPool* cp, + u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, @@ -2764,25 +2839,28 @@ } // 4347400: make sure there's no duplicate entry in the classes array + // Also, check for circular entries. + bool has_circularity = false; if (_need_verify && _major_version >= JAVA_1_5_VERSION) { - for(int i = 0; i < length * 4; i += 4) { - for(int j = i + 4; j < length * 4; j += 4) { - guarantee_property((inner_classes->at(i) != inner_classes->at(j) || - inner_classes->at(i+1) != inner_classes->at(j+1) || - inner_classes->at(i+2) != inner_classes->at(j+2) || - inner_classes->at(i+3) != inner_classes->at(j+3)), - "Duplicate entry in InnerClasses in class file %s", - CHECK_0); + has_circularity = check_inner_classes_circularity(cp, length * 4, CHECK_0); + if (has_circularity) { + // If circularity check failed then ignore InnerClasses attribute. + MetadataFactory::free_array<u2>(_loader_data, _inner_classes); + index = 0; + if (parsed_enclosingmethod_attribute) { + inner_classes = MetadataFactory::new_array<u2>(_loader_data, 2, CHECK_0); + _inner_classes = inner_classes; + } else { + _inner_classes = Universe::the_empty_short_array(); } } } - // Set EnclosingMethod class and method indexes. if (parsed_enclosingmethod_attribute) { inner_classes->at_put(index++, enclosing_method_class_index); inner_classes->at_put(index++, enclosing_method_method_index); } - assert(index == size, "wrong size"); + assert(index == size || has_circularity, "wrong size"); // Restore buffer's current position. cfs->set_current(current_mark); @@ -3051,6 +3129,7 @@ if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( + _cp, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, @@ -3717,16 +3796,6 @@ info->has_nonstatic_fields = has_nonstatic_fields; } -static bool relax_format_check_for(ClassLoaderData* loader_data) { - bool trusted = (loader_data->is_the_null_class_loader_data() || - SystemDictionary::is_ext_class_loader(loader_data->class_loader())); - bool need_verify = - // verifyAll - (BytecodeVerificationLocal && BytecodeVerificationRemote) || - // verifyRemote - (!BytecodeVerificationLocal && BytecodeVerificationRemote && !trusted); - return !need_verify; -} instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ClassLoaderData* loader_data, @@ -3873,7 +3942,7 @@ // Check if verification needs to be relaxed for this class file // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376) - _relax_verify = relax_format_check_for(_loader_data); + _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
--- a/src/share/vm/classfile/classFileParser.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/classFileParser.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -275,7 +275,12 @@ u2 parse_generic_signature_attribute(TRAPS); void parse_classfile_sourcefile_attribute(TRAPS); void parse_classfile_source_debug_extension_attribute(int length, TRAPS); - u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, + + // Check for circularity in InnerClasses attribute. + bool check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS); + + u2 parse_classfile_inner_classes_attribute(const ConstantPool* cp, + u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index,
--- a/src/share/vm/classfile/symbolTable.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/symbolTable.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, 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 @@ -224,7 +224,7 @@ // Pick hashing algorithm. unsigned int SymbolTable::hash_symbol(const char* s, int len) { return use_alternate_hashcode() ? - AltHashing::murmur3_32(seed(), (const jbyte*)s, len) : + AltHashing::halfsiphash_32(seed(), (const uint8_t*)s, len) : java_lang_String::hash_code(s, len); } @@ -650,7 +650,7 @@ // Pick hashing algorithm unsigned int StringTable::hash_string(const jchar* s, int len) { - return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : + return use_alternate_hashcode() ? AltHashing::halfsiphash_32(seed(), s, len) : java_lang_String::hash_code(s, len); }
--- a/src/share/vm/classfile/systemDictionary.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/systemDictionary.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, 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 @@ -1074,6 +1074,18 @@ return k(); } +static bool is_prohibited_package_slow(Symbol* class_name) { + // Caller has ResourceMark + int length; + jchar* unicode = class_name->as_unicode(length); + return (length >= 5 && + unicode[0] == 'j' && + unicode[1] == 'a' && + unicode[2] == 'v' && + unicode[3] == 'a' && + unicode[4] == '/'); +} + // Add a klass to the system from a stream (called by jni_DefineClass and // JVM_DefineClass). // Note: class_name can be NULL. In that case we do not know the name of @@ -1121,24 +1133,33 @@ if (!HAS_PENDING_EXCEPTION && !class_loader.is_null() && parsed_name != NULL && - parsed_name->utf8_length() >= (int)pkglen && - !strncmp((const char*)parsed_name->bytes(), pkg, pkglen)) { - // It is illegal to define classes in the "java." package from - // JVM_DefineClass or jni_DefineClass unless you're the bootclassloader + parsed_name->utf8_length() >= (int)pkglen) { ResourceMark rm(THREAD); - char* name = parsed_name->as_C_string(); - char* index = strrchr(name, '/'); - assert(index != NULL, "must be"); - *index = '\0'; // chop to just the package name - while ((index = strchr(name, '/')) != NULL) { - *index = '.'; // replace '/' with '.' in package name + bool prohibited; + const jbyte* base = parsed_name->base(); + if ((base[0] | base[1] | base[2] | base[3] | base[4]) & 0x80) { + prohibited = is_prohibited_package_slow(parsed_name); + } else { + char* name = parsed_name->as_C_string(); + prohibited = (strncmp(name, pkg, pkglen) == 0); } - const char* fmt = "Prohibited package name: %s"; - size_t len = strlen(fmt) + strlen(name); - char* message = NEW_RESOURCE_ARRAY(char, len); - jio_snprintf(message, len, fmt, name); - Exceptions::_throw_msg(THREAD_AND_LOCATION, - vmSymbols::java_lang_SecurityException(), message); + if (prohibited) { + // It is illegal to define classes in the "java." package from + // JVM_DefineClass or jni_DefineClass unless you're the bootclassloader + char* name = parsed_name->as_C_string(); + char* index = strrchr(name, '/'); + assert(index != NULL, "must be"); + *index = '\0'; // chop to just the package name + while ((index = strchr(name, '/')) != NULL) { + *index = '.'; // replace '/' with '.' in package name + } + const char* fmt = "Prohibited package name: %s"; + size_t len = strlen(fmt) + strlen(name); + char* message = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(message, len, fmt, name); + Exceptions::_throw_msg(THREAD_AND_LOCATION, + vmSymbols::java_lang_SecurityException(), message); + } } if (!HAS_PENDING_EXCEPTION) {
--- a/src/share/vm/classfile/verifier.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/verifier.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -101,7 +101,7 @@ BytecodeVerificationLocal : BytecodeVerificationRemote; } -bool Verifier::relax_access_for(oop loader) { +bool Verifier::relax_verify_for(oop loader) { bool trusted = java_lang_ClassLoader::is_trusted_loader(loader); bool need_verify = // verifyAll
--- a/src/share/vm/classfile/verifier.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/classfile/verifier.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -57,8 +57,8 @@ // -Xverify:all/none override this value static bool should_verify_for(oop class_loader, bool should_verify_class); - // Relax certain access checks to enable some broken 1.1 apps to run on 1.2. - static bool relax_access_for(oop class_loader); + // Relax certain verifier checks to enable some broken 1.1 apps to run on 1.2. + static bool relax_verify_for(oop class_loader); private: static bool is_eligible_for_verification(instanceKlassHandle klass, bool should_verify_class);
--- a/src/share/vm/compiler/disassembler.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/compiler/disassembler.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -247,19 +247,24 @@ const char* options() { return _option_buf; } }; -decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { - memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. - _output = output ? output : tty; - _code = code; - if (code != NULL && code->is_nmethod()) - _nm = (nmethod*) code; +decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) : + _nm((code != NULL && code->is_nmethod()) ? (nmethod*)code : NULL), + _code(code), + _strings(), + _output(output ? output : tty), + _start(NULL), + _end(NULL), + _print_raw(0), + // by default, output pc but not bytes: + _print_pc(true), + _print_bytes(false), + _cur_insn(NULL), + _total_ticks(0), + _bytes_per_line(Disassembler::pd_instruction_alignment()) +{ + memset(_option_buf, 0, sizeof(_option_buf)); _strings.copy(c); - // by default, output pc but not bytes: - _print_pc = true; - _print_bytes = false; - _bytes_per_line = Disassembler::pd_instruction_alignment(); - // parse the global option string: collect_options(Disassembler::pd_cpu_opts()); collect_options(PrintAssemblyOptions);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -3096,7 +3096,10 @@ } void do_object_work(oop obj) { - guarantee(!_g1h->obj_in_cs(obj), + guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || obj->is_oop(), + err_msg("Non-oop " PTR_FORMAT ", phase: %s, info: %d", + p2i((void*) obj), phase_str(), _info)); + guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->obj_in_cs(obj), err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", p2i((void*) obj), phase_str(), _info)); } @@ -3506,18 +3509,25 @@ template<bool scan> inline void CMTask::process_grey_object(oop obj) { assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); - assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } - size_t obj_size = obj->size(); - _words_scanned += obj_size; + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked((HeapWord*) obj), + "Any stolen object should be a slice or marked"); if (scan) { - obj->oop_iterate(_cm_oop_closure); + if (G1CMObjArrayProcessor::is_array_slice(obj)) { + _words_scanned += _objArray_processor.process_slice(obj); + } else if (G1CMObjArrayProcessor::should_be_sliced(obj)) { + _words_scanned += _objArray_processor.process_obj(obj); + } else { + size_t obj_size = obj->size(); + _words_scanned += obj_size; + obj->oop_iterate(_cm_oop_closure);; + } } statsOnly( ++_objs_scanned ); check_limits(); @@ -3877,6 +3887,8 @@ _worker_id, n); } for (int i = 0; i < n; ++i) { + assert(G1CMObjArrayProcessor::is_array_slice(buffer[i]) || buffer[i]->is_oop(), + err_msg("Element " PTR_FORMAT " must be an array slice or oop", p2i(buffer[i]))); bool success = _task_queue->push(buffer[i]); // We only call this when the local queue is empty or under a // given target limit. So, we do not expect this push to fail. @@ -3895,7 +3907,9 @@ } void CMTask::drain_local_queue(bool partially) { - if (has_aborted()) return; + if (has_aborted()) { + return; + } // Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out @@ -3923,10 +3937,6 @@ p2i((void*) obj)); } - assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" ); - assert(!_g1h->is_on_master_free_list( - _g1h->heap_region_containing((HeapWord*) obj)), "invariant"); - scan_object(obj); if (_task_queue->size() <= target_size || has_aborted()) { @@ -4427,8 +4437,6 @@ statsOnly( ++_steals ); - assert(_nextMarkBitMap->isMarked((HeapWord*) obj), - "any stolen object should be marked"); scan_object(obj); // And since we're towards the end, let's totally drain the @@ -4602,6 +4610,7 @@ CMTaskQueueSet* task_queues) : _g1h(G1CollectedHeap::heap()), _worker_id(worker_id), _cm(cm), + _objArray_processor(this), _claimed(false), _nextMarkBitMap(NULL), _hash_seed(17), _task_queue(task_queue),
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP #include "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp" #include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/shared/gcId.hpp" @@ -942,7 +943,7 @@ words_scanned_period = 12*1024, // the regular clock call is called once the number of visited // references reaches this limit - refs_reached_period = 384, + refs_reached_period = 1024, // initial value for the hash seed, used in the work stealing code init_hash_seed = 17, // how many entries will be transferred between global stack and @@ -950,6 +951,8 @@ global_stack_transfer_size = 16 }; + G1CMObjArrayProcessor _objArray_processor; + uint _worker_id; G1CollectedHeap* _g1h; ConcurrentMark* _cm; @@ -1110,6 +1113,9 @@ template<bool scan> void process_grey_object(oop obj); public: + // Apply the closure on the given area of the objArray. Return the number of words + // scanned. + inline size_t scan_objArray(objArrayOop obj, MemRegion mr); // It resets the task; it should be called right at the beginning of // a marking phase. void reset(CMBitMap* _nextMarkBitMap);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -27,6 +27,7 @@ #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" // Utility routine to set an exclusive range of cards on the given // card liveness bitmap @@ -224,11 +225,11 @@ inline void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; - assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); - assert(!_g1h->is_on_master_free_list( + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _g1h->is_in_g1_reserved(objAddr), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_on_master_free_list( _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant"); - assert(!_g1h->is_obj_ill(obj), "invariant"); - assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_obj_ill(obj), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked(objAddr), "invariant"); if (_cm->verbose_high()) { gclog_or_tty->print_cr("[%u] pushing " PTR_FORMAT, _worker_id, p2i((void*) obj)); @@ -365,6 +366,11 @@ } } +inline size_t CMTask::scan_objArray(objArrayOop obj, MemRegion mr) { + obj->oop_iterate(_cm_oop_closure, mr); + return mr.word_size(); +} + inline void ConcurrentMark::markPrev(oop p) { assert(!_prevMarkBitMap->isMarked((HeapWord*) p), "sanity"); // Note we are overriding the read-only view of the prev map here, via
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -0,0 +1,87 @@ +/* + * 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 "precompiled.hpp" +#include "gc_implementation/g1/concurrentMark.inline.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" + +oop G1CMObjArrayProcessor::encode_array_slice(HeapWord* addr) { + return oop((void*)((uintptr_t)addr | ArraySliceBit)); +} + +HeapWord* G1CMObjArrayProcessor::decode_array_slice(oop value) { + assert(is_array_slice(value), err_msg("Given value " PTR_FORMAT " is not an array slice", p2i(value))); + return (HeapWord*)((uintptr_t)(void*)value & ~ArraySliceBit); +} + +void G1CMObjArrayProcessor::push_array_slice(HeapWord* what) { + oop obj = encode_array_slice(what); + _task->push(obj); +} + +size_t G1CMObjArrayProcessor::process_array_slice(objArrayOop obj, HeapWord* start_from, size_t remaining) { + size_t words_to_scan = MIN2(remaining, ObjArrayMarkingStride); + + if (remaining > ObjArrayMarkingStride) { + push_array_slice(start_from + ObjArrayMarkingStride); + } + + // Then process current area. + MemRegion mr(start_from, words_to_scan); + return _task->scan_objArray(obj, mr); +} + +size_t G1CMObjArrayProcessor::process_obj(oop obj) { + assert(should_be_sliced(obj), err_msg("Must be an array object %d and large " SIZE_FORMAT, obj->is_objArray(), (size_t)obj->size())); + + return process_array_slice(objArrayOop(obj), (HeapWord*)obj, (size_t)objArrayOop(obj)->size()); +} + +size_t G1CMObjArrayProcessor::process_slice(oop obj) { + HeapWord* const decoded_address = decode_array_slice(obj); + + // Find the start address of the objArrayOop. + // Shortcut the BOT access if the given address is from a humongous object. The BOT + // slide is fast enough for "smaller" objects in non-humongous regions, but is slower + // than directly using heap region table. + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* r = g1h->heap_region_containing(decoded_address); + + HeapWord* const start_address = r->isHumongous() ? + r->humongous_start_region()->bottom() : + g1h->block_start(decoded_address); + + assert(oop(start_address)->is_objArray(), err_msg("Address " PTR_FORMAT " does not refer to an object array ", p2i(start_address))); + assert(start_address < decoded_address, + err_msg("Object start address " PTR_FORMAT " must be smaller than decoded address " PTR_FORMAT, + p2i(start_address), + p2i(decoded_address))); + + objArrayOop objArray = objArrayOop(start_address); + + size_t already_scanned = decoded_address - start_address; + size_t remaining = objArray->size() - already_scanned; + + return process_array_slice(objArray, decoded_address, remaining); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -0,0 +1,70 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP +#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP + +#include "oops/oopsHierarchy.hpp" +#include "memory/allocation.hpp" + +class CMTask; + +// Helper class to mark through large objArrays during marking in an efficient way. +// Instead of pushing large object arrays, we push continuations onto the +// mark stack. These continuations are identified by having their LSB set. +// This allows incremental processing of large objects. +class G1CMObjArrayProcessor VALUE_OBJ_CLASS_SPEC { +private: + // The bit mask for the continuation indicator of elements on the mark stack. + static const size_t ArraySliceBit = 1; + + // Reference to the task for doing the actual work. + CMTask* _task; + + // Encodes the given address as a continuation "oop". + oop encode_array_slice(HeapWord* addr); + // Remove the continuation marker from the given oop from the mark stack. + HeapWord* decode_array_slice(oop value); + + // Push the continuation at the given address onto the mark stack. + void push_array_slice(HeapWord* addr); + + // Process (apply the closure) on the given continuation of the given objArray. + size_t process_array_slice(objArrayOop const obj, HeapWord* start_from, size_t remaining); +public: + static bool is_array_slice(void* obj) { return ((uintptr_t)obj & ArraySliceBit) != 0; } + + static bool should_be_sliced(oop obj); + + G1CMObjArrayProcessor(CMTask* task) : _task(task) { + } + + // Process the given continuation "oop". Returns the number of words scanned. + size_t process_slice(oop obj); + // Start processing the given objArrayOop by scanning the header and pushing its + // continuation. + size_t process_obj(oop obj); +}; + +#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -0,0 +1,36 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP +#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP + +#include "oops/oop.inline.hpp" +#include "oops/oopsHierarchy.hpp" +#include "runtime/globals.hpp" + +inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) { + return obj->is_objArray() && ((size_t)((objArrayOop)obj)->size()) >= 2 * ObjArrayMarkingStride; +} + +#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP */
--- a/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -215,7 +215,7 @@ uintx G1StringDedupTable::_resize_count = 0; uintx G1StringDedupTable::_rehash_count = 0; -G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) : +G1StringDedupTable::G1StringDedupTable(size_t size, uint64_t hash_seed) : _size(size), _entries(0), _grow_threshold((uintx)(size * _grow_load_factor)), @@ -319,9 +319,8 @@ if (use_java_hash()) { hash = java_lang_String::hash_code(data, length); } else { - hash = AltHashing::murmur3_32(_table->_hash_seed, data, length); + hash = AltHashing::halfsiphash_32(_table->_hash_seed, (const uint16_t*)data, length); } - return hash; } @@ -600,7 +599,7 @@ " [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]\n" " [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " SIZE_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]\n" " [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]\n" - " [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]\n" + " [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: " UINT64_FORMAT "]\n" " [Age Threshold: " UINTX_FORMAT "]", G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), _table->_size, _min_size, _max_size,
--- a/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -38,8 +38,8 @@ class G1StringDedupEntry : public CHeapObj<mtGC> { private: G1StringDedupEntry* _next; - unsigned int _hash; - typeArrayOop _obj; + unsigned int _hash; + typeArrayOop _obj; public: G1StringDedupEntry() : @@ -119,8 +119,8 @@ // The hash seed also dictates which hash function to use. A // zero hash seed means we will use the Java compatible hash // function (which doesn't use a seed), and a non-zero hash - // seed means we use the murmur3 hash function. - jint _hash_seed; + // seed means we use the murmur3 and better hash function. + uint64_t _hash_seed; // Constants governing table resize/rehash/cache. static const size_t _min_size; @@ -137,7 +137,7 @@ static uintx _resize_count; static uintx _rehash_count; - G1StringDedupTable(size_t size, jint hash_seed = 0); + G1StringDedupTable(size_t size, uint64_t hash_seed = 0); ~G1StringDedupTable(); // Returns the hash bucket at the given index.
--- a/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -31,9 +31,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrEventClass.hpp" #include "memory/resourceArea.hpp" -#include "prims/jvmtiEnvBase.hpp" #include "prims/jvmtiExport.hpp" -#include "prims/jvmtiUtil.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/thread.inline.hpp" #include "utilities/exceptions.hpp" @@ -53,17 +51,19 @@ } } -static bool set_event_notification_mode(jvmtiEventMode mode, - jvmtiEvent event, - jthread event_thread, - ...) { - assert(jfr_jvmti_env != NULL, "invariant"); +static jvmtiError set_event_notification_mode(jvmtiEventMode mode, + jvmtiEvent event, + jthread event_thread, + ...) { + if (jfr_jvmti_env == NULL) { + return JVMTI_ERROR_NONE; + } const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } -static bool update_class_file_load_hook_event(jvmtiEventMode mode) { +static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) { return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); } @@ -116,23 +116,12 @@ return classes; } -// caller needs ResourceMark -static void log_and_throw(jvmtiError error, TRAPS) { +static void log_and_throw(TRAPS) { if (!HAS_PENDING_EXCEPTION) { DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); ThreadInVMfromNative tvmfn((JavaThread*)THREAD); - const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: "; - size_t length = sizeof base_error_msg; // includes terminating null - const char* const jvmti_error_name = JvmtiUtil::error_name(error); - assert(jvmti_error_name != NULL, "invariant"); - length += strlen(jvmti_error_name); - char* error_msg = NEW_RESOURCE_ARRAY(char, length); - jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name); - if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) { - JfrJavaSupport::throw_class_format_error(error_msg, THREAD); - } else { - JfrJavaSupport::throw_runtime_exception(error_msg, THREAD); - } + if (true) tty->print_cr("JfrJvmtiAgent::retransformClasses failed"); + JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD); } } @@ -147,15 +136,12 @@ } } -static bool is_valid_jvmti_phase() { - return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE; -} - void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { assert(env != NULL, "invariant"); - assert(classes_array != NULL, "invariant"); - assert(is_valid_jvmti_phase(), "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); + if (classes_array == NULL) { + return; + } const jint classes_count = env->GetArrayLength(classes_array); if (classes_count <= 0) { return; @@ -166,27 +152,27 @@ for (jint i = 0; i < classes_count; i++) { jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); check_exception_and_log(env, THREAD); - classes[i] = clz; - } - { + // inspecting the oop/klass requires a thread transition - ThreadInVMfromNative transition((JavaThread*)THREAD); - for (jint i = 0; i < classes_count; ++i) { - jclass clz = classes[i]; - if (!JdkJfrEvent::is_a(clz)) { + { + ThreadInVMfromNative transition((JavaThread*)THREAD); + if (JdkJfrEvent::is_a(clz)) { + // should have been tagged already + assert(JdkJfrEvent::is_subklass(clz), "invariant"); + } else { // outside the event hierarchy JdkJfrEvent::tag_as_host(clz); } } + + classes[i] = clz; } - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); - const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes); - if (result != JVMTI_ERROR_NONE) { - log_and_throw(result, THREAD); + if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { + log_and_throw(THREAD); } } -static bool register_callbacks(JavaThread* jt) { +static jvmtiError register_callbacks(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiEventCallbacks callbacks; @@ -195,10 +181,10 @@ callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } -static bool register_capabilities(JavaThread* jt) { +static jvmtiError register_capabilities(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiCapabilities capabilities; @@ -208,7 +194,7 @@ capabilities.can_retransform_any_class = 1; const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } static jint create_jvmti_env(JavaThread* jt) { @@ -219,14 +205,16 @@ return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); } -static bool unregister_callbacks(JavaThread* jt) { - assert(jfr_jvmti_env != NULL, "invariant"); +static jvmtiError unregister_callbacks(JavaThread* jt) { + if (jfr_jvmti_env == NULL) { + return JVMTI_ERROR_NONE; + } jvmtiEventCallbacks callbacks; /* Set empty callbacks */ memset(&callbacks, 0, sizeof(callbacks)); const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } JfrJvmtiAgent::JfrJvmtiAgent() {} @@ -234,17 +222,20 @@ JfrJvmtiAgent::~JfrJvmtiAgent() { JavaThread* jt = current_java_thread(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); + ThreadToNativeFromVM transition(jt); + update_class_file_load_hook_event(JVMTI_DISABLE); + unregister_callbacks(jt); if (jfr_jvmti_env != NULL) { - ThreadToNativeFromVM transition(jt); - update_class_file_load_hook_event(JVMTI_DISABLE); - unregister_callbacks(jt); jfr_jvmti_env->DisposeEnvironment(); jfr_jvmti_env = NULL; } + agent = NULL; } -static bool initialize(JavaThread* jt) { +static bool initialize() { + JavaThread* const jt = current_java_thread(); assert(jt != NULL, "invariant"); + assert(jt->thread_state() == _thread_in_vm, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); ThreadToNativeFromVM transition(jt); if (create_jvmti_env(jt) != JNI_OK) { @@ -252,38 +243,25 @@ return false; } assert(jfr_jvmti_env != NULL, "invariant"); - if (!register_capabilities(jt)) { - return false; - } - if (!register_callbacks(jt)) { + if (register_capabilities(jt) != JVMTI_ERROR_NONE) { return false; } - return update_class_file_load_hook_event(JVMTI_ENABLE); -} - -static void log_and_throw_illegal_state_exception(TRAPS) { - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); - const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence."; - if (true) { - tty->print_cr("%s\n", illegal_state_msg); - tty->print_cr("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE.\n"); - tty->print_cr("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START.\n"); + if (register_callbacks(jt) != JVMTI_ERROR_NONE) { + return false; } - JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD); + if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { + return false; + } + return true; } bool JfrJvmtiAgent::create() { - assert(agent == NULL, "invariant"); - JavaThread* const jt = current_java_thread(); - if (!is_valid_jvmti_phase()) { - log_and_throw_illegal_state_exception(jt); - return false; - } + assert(jfr_jvmti_env == NULL, "invariant"); agent = new JfrJvmtiAgent(); if (agent == NULL) { return false; } - if (!initialize(jt)) { + if (!initialize()) { delete agent; agent = NULL; return false; @@ -297,3 +275,4 @@ agent = NULL; } } +
--- a/src/share/vm/jfr/jfr.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/jfr.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -32,7 +32,6 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "runtime/java.hpp" -#include "utilities/defaultStream.hpp" bool Jfr::is_enabled() { return JfrRecorder::is_enabled(); @@ -46,21 +45,15 @@ return JfrRecorder::is_recording(); } -void Jfr::on_create_vm_1() { - if (!JfrRecorder::on_create_vm_1()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_1"); +void Jfr::on_vm_init() { + if (!JfrRecorder::on_vm_init()) { + vm_exit_during_initialization("Failure when starting JFR on_vm_init"); } } -void Jfr::on_create_vm_2() { - if (!JfrRecorder::on_create_vm_2()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_2"); - } -} - -void Jfr::on_create_vm_3() { - if (!JfrRecorder::on_create_vm_3()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_3"); +void Jfr::on_vm_start() { + if (!JfrRecorder::on_vm_start()) { + vm_exit_during_initialization("Failure when starting JFR on_vm_start"); } }
--- a/src/share/vm/jfr/jfr.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/jfr.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -43,9 +43,8 @@ static bool is_enabled(); static bool is_disabled(); static bool is_recording(); - static void on_create_vm_1(); - static void on_create_vm_2(); - static void on_create_vm_3(); + static void on_vm_init(); + static void on_vm_start(); static void on_unloading_classes(); static void on_thread_start(Thread* thread); static void on_thread_exit(Thread* thread);
--- a/src/share/vm/jfr/jni/jfrJavaSupport.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/jni/jfrJavaSupport.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -515,10 +515,6 @@ create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD); } -void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) { - create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD); -} - void JfrJavaSupport::abort(jstring errorMsg, Thread* t) { DEBUG_ONLY(check_java_thread_in_vm(t));
--- a/src/share/vm/jfr/jni/jfrJavaSupport.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/jni/jfrJavaSupport.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -81,7 +81,6 @@ static void throw_internal_error(const char* message, TRAPS); static void throw_out_of_memory_error(const char* message, TRAPS); static void throw_class_format_error(const char* message, TRAPS); - static void throw_runtime_exception(const char* message, TRAPS); static jlong jfr_thread_id(jobject target_thread);
--- a/src/share/vm/jfr/jni/jfrJniMethod.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/jni/jfrJniMethod.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -191,9 +191,7 @@ return JNI_TRUE; } if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) { - if (!thread->has_pending_exception()) { - JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); - } + JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); return JNI_FALSE; } return JNI_TRUE;
--- a/src/share/vm/jfr/recorder/jfrRecorder.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/recorder/jfrRecorder.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -44,9 +44,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/globals_extension.hpp" #include "utilities/growableArray.hpp" -#ifdef ASSERT -#include "prims/jvmtiEnvBase.hpp" -#endif bool JfrRecorder::_shutting_down = false; @@ -60,9 +57,7 @@ static bool enable() { assert(!_enabled, "invariant"); - if (!FlightRecorder) { - FLAG_SET_MGMT(bool, FlightRecorder, true); - } + FLAG_SET_MGMT(bool, FlightRecorder, true); _enabled = FlightRecorder; assert(_enabled, "invariant"); return _enabled; @@ -72,7 +67,7 @@ return _enabled; } -bool JfrRecorder::on_create_vm_1() { +bool JfrRecorder::on_vm_init() { if (!is_disabled()) { if (FlightRecorder || StartFlightRecording != NULL) { enable(); @@ -97,7 +92,7 @@ static void teardown_startup_support() { release_recordings(); - JfrOptionSet::release_start_flight_recording_options(); + JfrOptionSet::release_startup_recording_options(); } // Parsing options here to detect errors as soon as possible @@ -115,7 +110,7 @@ } static bool validate_recording_options(TRAPS) { - const GrowableArray<const char*>* options = JfrOptionSet::start_flight_recording_options(); + const GrowableArray<const char*>* options = JfrOptionSet::startup_recording_options(); if (options == NULL) { return true; } @@ -148,7 +143,7 @@ return true; } -static bool launch_command_line_recordings(TRAPS) { +static bool launch_recordings(TRAPS) { bool result = true; if (dcmd_recordings_array != NULL) { const int length = dcmd_recordings_array->length(); @@ -166,7 +161,7 @@ static bool is_cds_dump_requested() { // we will not be able to launch recordings if a cds dump is being requested - if (DumpSharedSpaces && (JfrOptionSet::start_flight_recording_options() != NULL)) { + if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) { warning("JFR will be disabled during CDS dumping"); teardown_startup_support(); return true; @@ -174,7 +169,7 @@ return false; } -bool JfrRecorder::on_create_vm_2() { +bool JfrRecorder::on_vm_start() { if (is_cds_dump_requested()) { return true; } @@ -201,14 +196,10 @@ if (!is_enabled()) { return true; } - return true; + + return launch_recordings(thread); } -bool JfrRecorder::on_create_vm_3() { - assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); - return launch_command_line_recordings(Thread::current()); - } - static bool _created = false; // @@ -275,6 +266,7 @@ } // subsystems +static JfrJvmtiAgent* _jvmti_agent = NULL; static JfrPostBox* _post_box = NULL; static JfrStorage* _storage = NULL; static JfrCheckpointManager* _checkpoint_manager = NULL;
--- a/src/share/vm/jfr/recorder/jfrRecorder.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/recorder/jfrRecorder.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -40,9 +40,6 @@ private: static bool _shutting_down; - static bool on_create_vm_1(); - static bool on_create_vm_2(); - static bool on_create_vm_3(); static bool create_checkpoint_manager(); static bool create_chunk_repository(); static bool create_java_event_writer(); @@ -57,6 +54,8 @@ static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); + static bool on_vm_start(); + static bool on_vm_init(); public: static bool is_enabled();
--- a/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -676,7 +676,7 @@ return false; } -static GrowableArray<const char*>* start_flight_recording_options_array = NULL; +static GrowableArray<const char*>* startup_recording_options_array = NULL; bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { assert(option != NULL, "invariant"); @@ -699,28 +699,28 @@ assert(value != NULL, "invariant"); const size_t value_length = strlen(value); - if (start_flight_recording_options_array == NULL) { - start_flight_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(8, true, mtTracing); + if (startup_recording_options_array == NULL) { + startup_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(8, true, mtTracing); } - assert(start_flight_recording_options_array != NULL, "invariant"); + assert(startup_recording_options_array != NULL, "invariant"); char* const startup_value = NEW_C_HEAP_ARRAY(char, value_length + 1, mtTracing); strncpy(startup_value, value, value_length + 1); assert(strncmp(startup_value, value, value_length) == 0, "invariant"); - start_flight_recording_options_array->append(startup_value); + startup_recording_options_array->append(startup_value); return false; } -const GrowableArray<const char*>* JfrOptionSet::start_flight_recording_options() { - return start_flight_recording_options_array; +const GrowableArray<const char*>* JfrOptionSet::startup_recording_options() { + return startup_recording_options_array; } -void JfrOptionSet::release_start_flight_recording_options() { - if (start_flight_recording_options_array != NULL) { - const int length = start_flight_recording_options_array->length(); +void JfrOptionSet::release_startup_recording_options() { + if (startup_recording_options_array != NULL) { + const int length = startup_recording_options_array->length(); for (int i = 0; i < length; ++i) { - FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i), mtTracing); + FREE_C_HEAP_ARRAY(char, startup_recording_options_array->at(i), mtTracing); } - delete start_flight_recording_options_array; - start_flight_recording_options_array = NULL; + delete startup_recording_options_array; + startup_recording_options_array = NULL; } }
--- a/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -80,8 +80,8 @@ static bool parse_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter); - static const GrowableArray<const char*>* start_flight_recording_options(); - static void release_start_flight_recording_options(); + static const GrowableArray<const char*>* startup_recording_options(); + static void release_startup_recording_options(); }; #endif // SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP
--- a/src/share/vm/jfr/writers/jfrWriterHost.inline.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/jfr/writers/jfrWriterHost.inline.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -70,7 +70,8 @@ inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len) { assert(value != NULL, "invariant"); assert(len > 0, "invariant"); - u1* const pos = ensure_size(sizeof(T) * len); + // Might need T + 1 size + u1* const pos = ensure_size(sizeof(T) * len + len); if (pos) { this->set_current_pos(write(value, len, pos)); } @@ -124,7 +125,8 @@ inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(const T* value, size_t len) { assert(value != NULL, "invariant"); assert(len > 0, "invariant"); - u1* const pos = ensure_size(sizeof(T) * len); + // Might need T + 1 size + u1* const pos = ensure_size(sizeof(T) * len + len); if (pos) { this->set_current_pos(BE::be_write(value, len, pos)); } @@ -137,10 +139,17 @@ _compressed_integers(compressed_integers()) { } +// Extra size added as a safety cushion when dimensioning memory. +// With varint encoding, the worst case is +// associated with writing negative values. +// For example, writing a negative s1 (-1) +// will encode as 0xff 0x0f (2 bytes). +static const size_t size_safety_cushion = 1; + template <typename BE, typename IE, typename WriterPolicyImpl > template <typename StorageType> inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, size_t size) : - WriterPolicyImpl(storage, size), + WriterPolicyImpl(storage, size + size_safety_cushion), _compressed_integers(compressed_integers()) { } @@ -150,30 +159,19 @@ _compressed_integers(compressed_integers()) { } -// Extra size added as a safety cushion when dimensioning memory. -// With varint encoding, the worst case is -// associated with writing negative values. -// For example, writing a negative s1 (-1) -// will encode as 0xff 0x0f (2 bytes). -// In this example, the sizeof(T) == 1 and length == 1, -// but the implementation will need to dimension -// 2 bytes for the encoding. -// Hopefully, negative values should be relatively rare. -static const size_t size_safety_cushion = 1; - template <typename BE, typename IE, typename WriterPolicyImpl> -inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) { +inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested_size) { if (!this->is_valid()) { // cancelled return NULL; } - if (this->available_size() < requested + size_safety_cushion) { - if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) { + if (this->available_size() < requested_size) { + if (!this->accommodate(this->used_size(), requested_size)) { this->cancel(); return NULL; } } - assert(requested + size_safety_cushion <= this->available_size(), "invariant"); + assert(requested_size <= this->available_size(), "invariant"); return this->current_pos(); }
--- a/src/share/vm/memory/filemap.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/memory/filemap.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -125,7 +125,7 @@ } else { // Get the hash value. Use a static seed because the hash needs to return the same // value over multiple jvm invocations. - unsigned int hash = AltHashing::murmur3_32(8191, (const jbyte*)vm_version, version_len); + uint32_t hash = AltHashing::halfsiphash_32(8191, (const uint8_t*)vm_version, version_len); // Truncate the ident, saving room for the 8 hex character hash value. strncpy(header_version, vm_version, JVM_IDENT_MAX-9);
--- a/src/share/vm/memory/metaspaceShared.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/memory/metaspaceShared.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -723,12 +723,15 @@ int class_list_path_len = (int)strlen(class_list_path_str); if (class_list_path_len >= 3) { if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) { - strcat(class_list_path_str, os::file_separator()); - strcat(class_list_path_str, "lib"); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%slib", os::file_separator()); + class_list_path_len += 4; } } - strcat(class_list_path_str, os::file_separator()); - strcat(class_list_path_str, "classlist"); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%sclasslist", os::file_separator()); class_list_path = class_list_path_str; } else { class_list_path = SharedClassListFile;
--- a/src/share/vm/oops/constantPool.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/oops/constantPool.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -504,7 +504,7 @@ } -Symbol* ConstantPool::klass_name_at(int which) { +Symbol* ConstantPool::klass_name_at(int which) const { assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), "Corrupted constant pool"); // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
--- a/src/share/vm/oops/constantPool.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/oops/constantPool.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -128,7 +128,7 @@ private: intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); } - CPSlot slot_at(int which) { + CPSlot slot_at(int which) const { assert(is_within_bounds(which), "index out of bounds"); // Uses volatile because the klass slot changes without a lock. volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which)); @@ -356,7 +356,7 @@ return klass_at_impl(h_this, which, THREAD); } - Symbol* klass_name_at(int which); // Returns the name, w/o resolving. + Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving. Klass* resolved_klass_at(int which) const { // Used by Compiler guarantee(tag_at(which).is_klass(), "Corrupted constant pool");
--- a/src/share/vm/oops/oop.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/oops/oop.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -111,7 +111,7 @@ jchar* chars = java_lang_String::as_unicode_string(this, length, THREAD); if (chars != NULL) { // Use alternate hashing algorithm on the string - return AltHashing::murmur3_32(seed, chars, length); + return AltHashing::halfsiphash_32(seed, chars, length); } else { vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "unable to create Unicode strings for String table rehash"); return 0;
--- a/src/share/vm/oops/symbol.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/oops/symbol.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -210,7 +210,7 @@ unsigned int Symbol::new_hash(juint seed) { ResourceMark rm; // Use alternate hashing algorithm on this symbol. - return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length()); + return AltHashing::halfsiphash_32(seed, (const uint8_t*)as_C_string(), utf8_length()); } void Symbol::increment_refcount() {
--- a/src/share/vm/opto/addnode.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/addnode.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -844,6 +844,14 @@ return TypeInt::make( MAX2(r0->_lo,r1->_lo), MAX2(r0->_hi,r1->_hi), MAX2(r0->_widen,r1->_widen) ); } +// Check if addition of an integer with type 't' and a constant 'c' can overflow +static bool can_overflow(const TypeInt* t, jint c) { + jint t_lo = t->_lo; + jint t_hi = t->_hi; + return ((c < 0 && (java_add(t_lo, c) > t_lo)) || + (c > 0 && (java_add(t_hi, c) < t_hi))); +} + //============================================================================= //------------------------------Idealize--------------------------------------- // MINs show up in range-check loop limit calculations. Look for @@ -866,7 +874,7 @@ // Get left input & constant Node *x = l; - int x_off = 0; + jint x_off = 0; if( x->Opcode() == Op_AddI && // Check for "x+c0" and collect constant x->in(2)->is_Con() ) { const Type *t = x->in(2)->bottom_type(); @@ -877,7 +885,7 @@ // Scan a right-spline-tree for MINs Node *y = r; - int y_off = 0; + jint y_off = 0; // Check final part of MIN tree if( y->Opcode() == Op_AddI && // Check for "y+c1" and collect constant y->in(2)->is_Con() ) { @@ -891,6 +899,7 @@ return this; } + const TypeInt* tx = phase->type(x)->isa_int(); if( r->Opcode() == Op_MinI ) { assert( r != r->in(2), "dead loop in MinINode::Ideal" ); @@ -907,18 +916,23 @@ if( x->_idx > y->_idx ) return new (phase->C) MinINode(r->in(1),phase->transform(new (phase->C) MinINode(l,r->in(2)))); - // See if covers: MIN2(x+c0,MIN2(y+c1,z)) - if( !phase->eqv(x,y) ) return NULL; - // If (y == x) transform MIN2(x+c0, MIN2(x+c1,z)) into - // MIN2(x+c0 or x+c1 which less, z). - return new (phase->C) MinINode(phase->transform(new (phase->C) AddINode(x,phase->intcon(MIN2(x_off,y_off)))),r->in(2)); + // Transform MIN2(x + c0, MIN2(x + c1, z)) into MIN2(x + MIN2(c0, c1), z) + // if x == y and the additions can't overflow. + if (phase->eqv(x,y) && + !can_overflow(tx, x_off) && + !can_overflow(tx, y_off)) { + return new (phase->C) MinINode(phase->transform(new (phase->C) AddINode(x, phase->intcon(MIN2(x_off, y_off)))), r->in(2)); + } } else { - // See if covers: MIN2(x+c0,y+c1) - if( !phase->eqv(x,y) ) return NULL; - // If (y == x) transform MIN2(x+c0,x+c1) into x+c0 or x+c1 which less. - return new (phase->C) AddINode(x,phase->intcon(MIN2(x_off,y_off))); + // Transform MIN2(x + c0, y + c1) into x + MIN2(c0, c1) + // if x == y and the additions can't overflow. + if (phase->eqv(x,y) && + !can_overflow(tx, x_off) && + !can_overflow(tx, y_off)) { + return new (phase->C) AddINode(x,phase->intcon(MIN2(x_off,y_off))); + } } - + return NULL; } //------------------------------add_ring---------------------------------------
--- a/src/share/vm/opto/compile.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/compile.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1164,6 +1164,9 @@ _expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL); _range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL); register_library_intrinsics(); +#ifdef ASSERT + _type_verify_symmetry = true; +#endif } //---------------------------init_start----------------------------------------
--- a/src/share/vm/opto/compile.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/compile.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -1224,6 +1224,9 @@ // Auxiliary method for randomized fuzzing/stressing static bool randomized_select(int count); +#ifdef ASSERT + bool _type_verify_symmetry; +#endif }; #endif // SHARE_VM_OPTO_COMPILE_HPP
--- a/src/share/vm/opto/loopTransform.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/loopTransform.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1530,65 +1530,78 @@ } //------------------------------adjust_limit----------------------------------- -// Helper function for add_constraint(). -Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl, bool round_up) { - // Compute "I :: (limit-offset)/scale" - Node *con = new (C) SubINode(rc_limit, offset); - register_new_node(con, pre_ctrl); - Node *X = new (C) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); +// Helper function that computes new loop limit as (rc_limit-offset)/scale +Node* PhaseIdealLoop::adjust_limit(bool is_positive_stride, Node* scale, Node* offset, Node* rc_limit, Node* old_limit, Node* pre_ctrl, bool round) { + Node* sub = new (C) SubLNode(rc_limit, offset); + register_new_node(sub, pre_ctrl); + Node* limit = new (C) DivLNode(NULL, sub, scale); + register_new_node(limit, pre_ctrl); - // When the absolute value of scale is greater than one, the integer - // division may round limit down so add one to the limit. - if (round_up) { - X = new (C) AddINode(X, _igvn.intcon(1)); - register_new_node(X, pre_ctrl); + // When the absolute value of scale is greater than one, the division + // may round limit down/up, so add/sub one to/from the limit. + if (round) { + limit = new (C) AddLNode(limit, _igvn.longcon(is_positive_stride ? -1 : 1)); + register_new_node(limit, pre_ctrl); } - // Adjust loop limit - loop_limit = (stride_con > 0) - ? (Node*)(new (C) MinINode(loop_limit, X)) - : (Node*)(new (C) MaxINode(loop_limit, X)); - register_new_node(loop_limit, pre_ctrl); - return loop_limit; + // Clamp the limit to handle integer under-/overflows. + // When reducing the limit, clamp to [min_jint, old_limit]: + // MIN(old_limit, MAX(limit, min_jint)) + // When increasing the limit, clamp to [old_limit, max_jint]: + // MAX(old_limit, MIN(limit, max_jint)) + Node* cmp = new (C) CmpLNode(limit, _igvn.longcon(is_positive_stride ? min_jint : max_jint)); + register_new_node(cmp, pre_ctrl); + Node* bol = new (C) BoolNode(cmp, is_positive_stride ? BoolTest::lt : BoolTest::gt); + register_new_node(bol, pre_ctrl); + limit = new (C) ConvL2INode(limit); + register_new_node(limit, pre_ctrl); + limit = new (C) CMoveINode(bol, limit, _igvn.intcon(is_positive_stride ? min_jint : max_jint), TypeInt::INT); + register_new_node(limit, pre_ctrl); + + limit = is_positive_stride ? (Node*)(new (C) MinINode(old_limit, limit)) + : (Node*)(new (C) MaxINode(old_limit, limit)); + register_new_node(limit, pre_ctrl); + return limit; } //------------------------------add_constraint--------------------------------- // Constrain the main loop iterations so the conditions: -// low_limit <= scale_con * I + offset < upper_limit -// always holds true. That is, either increase the number of iterations in -// the pre-loop or the post-loop until the condition holds true in the main -// loop. Stride, scale, offset and limit are all loop invariant. Further, -// stride and scale are constants (offset and limit often are). -void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset, Node *low_limit, Node *upper_limit, Node *pre_ctrl, Node **pre_limit, Node **main_limit ) { - // For positive stride, the pre-loop limit always uses a MAX function - // and the main loop a MIN function. For negative stride these are - // reversed. +// low_limit <= scale_con*I + offset < upper_limit +// always hold true. That is, either increase the number of iterations in the +// pre-loop or reduce the number of iterations in the main-loop until the condition +// holds true in the main-loop. Stride, scale, offset and limit are all loop +// invariant. Further, stride and scale are constants (offset and limit often are). +void PhaseIdealLoop::add_constraint(jlong stride_con, jlong scale_con, Node* offset, Node* low_limit, Node* upper_limit, Node* pre_ctrl, Node** pre_limit, Node** main_limit) { + assert(_igvn.type(offset)->isa_long() != NULL && _igvn.type(low_limit)->isa_long() != NULL && + _igvn.type(upper_limit)->isa_long() != NULL, "arguments should be long values"); - // Also for positive stride*scale the affine function is increasing, so the - // pre-loop must check for underflow and the post-loop for overflow. - // Negative stride*scale reverses this; pre-loop checks for overflow and - // post-loop for underflow. + // For a positive stride, we need to reduce the main-loop limit and + // increase the pre-loop limit. This is reversed for a negative stride. + bool is_positive_stride = (stride_con > 0); - Node *scale = _igvn.intcon(scale_con); + // If the absolute scale value is greater one, division in 'adjust_limit' may require + // rounding. Make sure the ABS method correctly handles min_jint. + // Only do this for the pre-loop, one less iteration of the main loop doesn't hurt. + bool round = ABS(scale_con) > 1; + + Node* scale = _igvn.longcon(scale_con); set_ctrl(scale, C->root()); if ((stride_con^scale_con) >= 0) { // Use XOR to avoid overflow + // Positive stride*scale: the affine function is increasing, + // the pre-loop checks for underflow and the post-loop for overflow. + // The overflow limit: scale*I+offset < upper_limit - // For main-loop compute + // For the main-loop limit compute: // ( if (scale > 0) /* and stride > 0 */ // I < (upper_limit-offset)/scale // else /* scale < 0 and stride < 0 */ // I > (upper_limit-offset)/scale // ) - // - // (upper_limit-offset) may overflow or underflow. - // But it is fine since main loop will either have - // less iterations or will be skipped in such case. - *main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl, false); + *main_limit = adjust_limit(is_positive_stride, scale, offset, upper_limit, *main_limit, pre_ctrl, false); - // The underflow limit: low_limit <= scale*I+offset. - // For pre-loop compute + // The underflow limit: low_limit <= scale*I+offset + // For the pre-loop limit compute: // NOT(scale*I+offset >= low_limit) // scale*I+offset < low_limit // ( if (scale > 0) /* and stride > 0 */ @@ -1596,40 +1609,13 @@ // else /* scale < 0 and stride < 0 */ // I > (low_limit-offset)/scale // ) + *pre_limit = adjust_limit(!is_positive_stride, scale, offset, low_limit, *pre_limit, pre_ctrl, round); + } else { + // Negative stride*scale: the affine function is decreasing, + // the pre-loop checks for overflow and the post-loop for underflow. - if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; - // We need this guard when scale*pre_limit+offset >= limit - // due to underflow. So we need execute pre-loop until - // scale*I+offset >= min_int. But (min_int-offset) will - // underflow when offset > 0 and X will be > original_limit - // when stride > 0. To avoid it we replace positive offset with 0. - // - // Also (min_int+1 == -max_int) is used instead of min_int here - // to avoid problem with scale == -1 (min_int/(-1) == min_int). - Node* shift = _igvn.intcon(31); - set_ctrl(shift, C->root()); - Node* sign = new (C) RShiftINode(offset, shift); - register_new_node(sign, pre_ctrl); - offset = new (C) AndINode(offset, sign); - register_new_node(offset, pre_ctrl); - } else { - assert(low_limit->get_int() == 0, "wrong low limit for range check"); - // The only problem we have here when offset == min_int - // since (0-min_int) == min_int. It may be fine for stride > 0 - // but for stride < 0 X will be < original_limit. To avoid it - // max(pre_limit, original_limit) is used in do_range_check(). - } - // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); - *pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl, - scale_con > 1 && stride_con > 0); - - } else { // stride_con*scale_con < 0 - // For negative stride*scale pre-loop checks for overflow and - // post-loop for underflow. - // // The overflow limit: scale*I+offset < upper_limit - // For pre-loop compute + // For the pre-loop limit compute: // NOT(scale*I+offset < upper_limit) // scale*I+offset >= upper_limit // scale*I+offset+1 > upper_limit @@ -1638,58 +1624,24 @@ // else /* scale > 0 and stride < 0 */ // I > (upper_limit-(offset+1))/scale // ) - // - // (upper_limit-offset-1) may underflow or overflow. - // To avoid it min(pre_limit, original_limit) is used - // in do_range_check() for stride > 0 and max() for < 0. - Node *one = _igvn.intcon(1); + Node* one = _igvn.longcon(1); set_ctrl(one, C->root()); - - Node *plus_one = new (C) AddINode(offset, one); + Node* plus_one = new (C) AddLNode(offset, one); register_new_node( plus_one, pre_ctrl ); - // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); - *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl, - scale_con < -1 && stride_con > 0); + *pre_limit = adjust_limit(!is_positive_stride, scale, plus_one, upper_limit, *pre_limit, pre_ctrl, round); - if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; - // We need this guard when scale*main_limit+offset >= limit - // due to underflow. So we need execute main-loop while - // scale*I+offset+1 > min_int. But (min_int-offset-1) will - // underflow when (offset+1) > 0 and X will be < main_limit - // when scale < 0 (and stride > 0). To avoid it we replace - // positive (offset+1) with 0. - // - // Also (min_int+1 == -max_int) is used instead of min_int here - // to avoid problem with scale == -1 (min_int/(-1) == min_int). - Node* shift = _igvn.intcon(31); - set_ctrl(shift, C->root()); - Node* sign = new (C) RShiftINode(plus_one, shift); - register_new_node(sign, pre_ctrl); - plus_one = new (C) AndINode(plus_one, sign); - register_new_node(plus_one, pre_ctrl); - } else { - assert(low_limit->get_int() == 0, "wrong low limit for range check"); - // The only problem we have here when offset == max_int - // since (max_int+1) == min_int and (0-min_int) == min_int. - // But it is fine since main loop will either have - // less iterations or will be skipped in such case. - } - // The underflow limit: low_limit <= scale*I+offset. - // For main-loop compute + // The underflow limit: low_limit <= scale*I+offset + // For the main-loop limit compute: // scale*I+offset+1 > low_limit // ( if (scale < 0) /* and stride > 0 */ // I < (low_limit-(offset+1))/scale // else /* scale > 0 and stride < 0 */ // I > (low_limit-(offset+1))/scale // ) - - *main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl, - false); + *main_limit = adjust_limit(is_positive_stride, scale, plus_one, low_limit, *main_limit, pre_ctrl, false); } } - //------------------------------is_scaled_iv--------------------------------- // Return true if exp is a constant times an induction var bool PhaseIdealLoop::is_scaled_iv(Node* exp, Node* iv, int* p_scale) { @@ -1854,22 +1806,14 @@ // Must know if its a count-up or count-down loop int stride_con = cl->stride_con(); - Node *zero = _igvn.intcon(0); - Node *one = _igvn.intcon(1); + Node* zero = _igvn.longcon(0); + Node* one = _igvn.longcon(1); // Use symmetrical int range [-max_jint,max_jint] - Node *mini = _igvn.intcon(-max_jint); + Node* mini = _igvn.longcon(-max_jint); set_ctrl(zero, C->root()); set_ctrl(one, C->root()); set_ctrl(mini, C->root()); - // Range checks that do not dominate the loop backedge (ie. - // conditionally executed) can lengthen the pre loop limit beyond - // the original loop limit. To prevent this, the pre limit is - // (for stride > 0) MINed with the original loop limit (MAXed - // stride < 0) when some range_check (rc) is conditionally - // executed. - bool conditional_rc = false; - // Check loop body for tests of trip-counter plus loop-invariant vs // loop-invariant. for( uint i = 0; i < loop->_body.size(); i++ ) { @@ -1948,15 +1892,20 @@ // stride_con and scale_con can be negative which will flip about the // sense of the test. + // Perform the limit computations in jlong to avoid overflow + jlong lscale_con = scale_con; + Node* int_offset = offset; + offset = new (C) ConvI2LNode(offset); + register_new_node(offset, pre_ctrl); + Node* int_limit = limit; + limit = new (C) ConvI2LNode(limit); + register_new_node(limit, pre_ctrl); + // Adjust pre and main loop limits to guard the correct iteration set if( cmp->Opcode() == Op_CmpU ) {// Unsigned compare is really 2 tests if( b_test._test == BoolTest::lt ) { // Range checks always use lt // The underflow and overflow limits: 0 <= scale*I+offset < limit - add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit ); - if (!conditional_rc) { - // (0-offset)/scale could be outside of loop iterations range. - conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; - } + add_constraint(stride_con, lscale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit); } else { #ifndef PRODUCT if( PrintOpto ) @@ -1970,16 +1919,16 @@ // Fall into GE case case BoolTest::ge: // Convert (I*scale+offset) >= Limit to (I*(-scale)+(-offset)) <= -Limit - scale_con = -scale_con; - offset = new (C) SubINode( zero, offset ); + lscale_con = -lscale_con; + offset = new (C) SubLNode(zero, offset); register_new_node( offset, pre_ctrl ); - limit = new (C) SubINode( zero, limit ); + limit = new (C) SubLNode(zero, limit); register_new_node( limit, pre_ctrl ); // Fall into LE case case BoolTest::le: if (b_test._test != BoolTest::gt) { // Convert X <= Y to X < Y+1 - limit = new (C) AddINode( limit, one ); + limit = new (C) AddLNode(limit, one); register_new_node( limit, pre_ctrl ); } // Fall into LT case @@ -1987,13 +1936,7 @@ // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. - add_constraint( stride_con, scale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit ); - if (!conditional_rc) { - // ((MIN_INT+1)-offset)/scale could be outside of loop iterations range. - // Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could - // still be outside of loop range. - conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; - } + add_constraint(stride_con, lscale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit); break; default: #ifndef PRODUCT @@ -2029,7 +1972,8 @@ } // Update loop limits - if (conditional_rc) { + if (pre_limit != orig_limit) { + // Computed pre-loop limit can be outside of loop iterations range. pre_limit = (stride_con > 0) ? (Node*)new (C) MinINode(pre_limit, orig_limit) : (Node*)new (C) MaxINode(pre_limit, orig_limit); register_new_node(pre_limit, pre_ctrl);
--- a/src/share/vm/opto/loopnode.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/loopnode.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -961,9 +961,9 @@ // always holds true. That is, either increase the number of iterations in // the pre-loop or the post-loop until the condition holds true in the main // loop. Scale_con, offset and limit are all loop invariant. - void add_constraint( int stride_con, int scale_con, Node *offset, Node *low_limit, Node *upper_limit, Node *pre_ctrl, Node **pre_limit, Node **main_limit ); + void add_constraint(jlong stride_con, jlong scale_con, Node* offset, Node* low_limit, Node* upper_limit, Node* pre_ctrl, Node** pre_limit, Node** main_limit); // Helper function for add_constraint(). - Node* adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl, bool round_up); + Node* adjust_limit(bool reduce, Node* scale, Node* offset, Node* rc_limit, Node* old_limit, Node* pre_ctrl, bool round); // Partially peel loop up through last_peel node. bool partial_peel( IdealLoopTree *loop, Node_List &old_new );
--- a/src/share/vm/opto/output.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/output.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1672,6 +1672,8 @@ } if (method() != NULL) { method()->print_metadata(); + } else if (stub_name() != NULL) { + tty->print_cr("Generating RuntimeStub - %s", stub_name()); } dump_asm(node_offsets, node_offset_limit); if (xtty != NULL) {
--- a/src/share/vm/opto/type.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/type.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -668,6 +668,35 @@ #endif +void Type::check_symmetrical(const Type *t, const Type *mt) const { +#ifdef ASSERT + assert(mt == t->xmeet(this), "meet not commutative"); + const Type* dual_join = mt->_dual; + const Type *t2t = dual_join->xmeet(t->_dual); + const Type *t2this = dual_join->xmeet(this->_dual); + + // Interface meet Oop is Not Symmetric: + // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull + // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull + + if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this->_dual) ) { + tty->print_cr("=== Meet Not Symmetric ==="); + tty->print("t = "); t->dump(); tty->cr(); + tty->print("this= "); dump(); tty->cr(); + tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); + + tty->print("t_dual= "); t->_dual->dump(); tty->cr(); + tty->print("this_dual= "); _dual->dump(); tty->cr(); + tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); + + tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); + tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); + + fatal("meet not symmetric" ); + } +#endif +} + //------------------------------meet------------------------------------------- // Compute the MEET of two types. NOT virtual. It enforces that meet is // commutative and the lattice is symmetric. @@ -685,33 +714,28 @@ t = t->maybe_remove_speculative(include_speculative); const Type *mt = this_t->xmeet(t); +#ifdef ASSERT if (isa_narrowoop() || t->isa_narrowoop()) return mt; if (isa_narrowklass() || t->isa_narrowklass()) return mt; -#ifdef ASSERT - assert(mt == t->xmeet(this_t), "meet not commutative"); - const Type* dual_join = mt->_dual; - const Type *t2t = dual_join->xmeet(t->_dual); - const Type *t2this = dual_join->xmeet(this_t->_dual); - - // Interface meet Oop is Not Symmetric: - // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull - // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull - - if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this_t->_dual) ) { - tty->print_cr("=== Meet Not Symmetric ==="); - tty->print("t = "); t->dump(); tty->cr(); - tty->print("this= "); this_t->dump(); tty->cr(); - tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); - - tty->print("t_dual= "); t->_dual->dump(); tty->cr(); - tty->print("this_dual= "); this_t->_dual->dump(); tty->cr(); - tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); - - tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); - tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); - - fatal("meet not symmetric" ); + Compile* C = Compile::current(); + if (!C->_type_verify_symmetry) { + return mt; } + this_t->check_symmetrical(t, mt); + // In the case of an array, computing the meet above, caused the + // computation of the meet of the elements which at verification + // time caused the computation of the meet of the dual of the + // elements. Computing the meet of the dual of the arrays here + // causes the meet of the dual of the elements to be computed which + // would cause the meet of the dual of the dual of the elements, + // that is the meet of the elements already computed above to be + // computed. Avoid redundant computations by requesting no + // verification. + C->_type_verify_symmetry = false; + const Type *mt_dual = this_t->_dual->xmeet(t->_dual); + this_t->_dual->check_symmetrical(t->_dual, mt_dual); + assert(!C->_type_verify_symmetry, "shouldn't have changed"); + C->_type_verify_symmetry = true; #endif return mt; } @@ -3966,10 +3990,10 @@ (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { - if (above_centerline(ptr)) { + if (above_centerline(ptr) || (tary->_elem->make_ptr() && above_centerline(tary->_elem->make_ptr()->_ptr))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); } - return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); + return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } bool xk = false;
--- a/src/share/vm/opto/type.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/opto/type.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -165,6 +165,7 @@ #endif const Type *meet_helper(const Type *t, bool include_speculative) const; + void check_symmetrical(const Type *t, const Type *mt) const; protected: // Each class of type is also identified by its base.
--- a/src/share/vm/prims/jniCheck.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/prims/jniCheck.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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 @@ -431,21 +431,20 @@ size_t sz; void* orig_result = check_wrapped_array(thr, fn_name, obj, carray, &sz); switch (mode) { + // As we never make copies, mode 0 and JNI_COMMIT are the same. case 0: - memcpy(orig_result, carray, sz); - GuardedMemory::free_copy(carray); - break; case JNI_COMMIT: memcpy(orig_result, carray, sz); break; case JNI_ABORT: - GuardedMemory::free_copy(carray); break; default: tty->print_cr("%s: Unrecognized mode %i releasing array " PTR_FORMAT " elements " PTR_FORMAT, fn_name, mode, p2i(obj), p2i(carray)); NativeReportJNIFatalError(thr, "Unrecognized array release mode"); } + // We always need to release the copy we made with GuardedMemory + GuardedMemory::free_copy(carray); return orig_result; }
--- a/src/share/vm/prims/jvm.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/prims/jvm.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -525,6 +525,17 @@ JVM_END +JVM_ENTRY_NO_ENV(jboolean, JVM_IsUseContainerSupport(void)) + JVMWrapper("JVM_IsUseContainerSupport"); +#ifdef TARGET_OS_FAMILY_linux + if (UseContainerSupport) { + return JNI_TRUE; + } +#endif + return JNI_FALSE; +JVM_END + + // java.lang.Throwable //////////////////////////////////////////////////////
--- a/src/share/vm/prims/jvm.h Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/prims/jvm.h Tue Oct 27 06:33:36 2020 +0000 @@ -202,6 +202,9 @@ JNIEXPORT jint JNICALL JVM_ActiveProcessorCount(void); +JNIEXPORT jboolean JNICALL +JVM_IsUseContainerSupport(void); + JNIEXPORT void * JNICALL JVM_LoadLibrary(const char *name);
--- a/src/share/vm/prims/nativeLookup.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/prims/nativeLookup.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -61,27 +61,118 @@ #endif -static void mangle_name_on(outputStream* st, Symbol* name, int begin, int end) { +/* + +The JNI specification defines the mapping from a Java native method name to +a C native library implementation function name as follows: + + The mapping produces a native method name by concatenating the following components + derived from a `native` method declaration: + + 1. the prefix Java_ + 2. given the binary name, in internal form, of the class which declares the native method: + the result of escaping the name. + 3. an underscore ("_") + 4. the escaped method name + 5. if the native method declaration is overloaded: two underscores ("__") followed by the + escaped parameter descriptor (JVMS 4.3.3) of the method declaration. + + Escaping leaves every alphanumeric ASCII character (A-Za-z0-9) unchanged, and replaces each + UTF-16 code unit n the table below with the corresponding escape sequence. If the name to be + escaped contains a surrogate pair, then the high-surrogate code unit and the low-surrogate code + unit are escaped separately. The result of escaping is a string consisting only of the ASCII + characters A-Za-z0-9 and underscore. + + ------------------------------ ------------------------------------ + UTF-16 code unit Escape sequence + ------------------------------ ------------------------------------ + Forward slash (/, U+002F) _ + Underscore (_, U+005F) _1 + Semicolon (;, U+003B) _2 + Left square bracket ([, U+005B) _3 + Any UTF-16 code unit \u_WXYZ_ that does not _0wxyz where w, x, y, and z are the lower-case + represent alphanumeric ASCII (A-Za-z0-9), forms of the hexadecimal digits W, X, Y, and Z. + forward slash, underscore, semicolon, (For example, U+ABCD becomes _0abcd.) + or left square bracket + ------------------------------ ------------------------------------ + + Note that escape sequences can safely begin _0, _1, etc, because class and method + names in Java source code never begin with a number. However, that is not the case in + class files that were not generated from Java source code. + + To preserve the 1:1 mapping to a native method name, the VM checks the resulting name as + follows. If the process of escaping any precursor string from the native method declaration + (class or method name, or argument type) causes a "0", "1", "2", or "3" character + from the precursor string to appear unchanged in the result *either* immediately after an + underscore *or* at the beginning of the escaped string (where it will follow an underscore + in the fully assembled name), then the escaping process is said to have "failed". + In such cases, no native library search is performed, and the attempt to link the native + method invocation will throw UnsatisfiedLinkError. + + +For example: + + package/my_class/method + +and + + package/my/1class/method + +both map to + + Java_package_my_1class_method + +To address this potential conflict we need only check if the character after +/ is a digit 0..3, or if the first character after an injected '_' seperator +is a digit 0..3. If we encounter an invalid identifier we reset the +stringStream and return false. Otherwise the stringStream contains the mapped +name and we return true. + +To address legacy compatibility, the UseLegacyJNINameEscaping flag can be set +which skips the extra checks. + +*/ +static bool map_escaped_name_on(stringStream* st, Symbol* name, int begin, int end) { char* bytes = (char*)name->bytes() + begin; char* end_bytes = (char*)name->bytes() + end; + bool check_escape_char = true; // initially true as first character here follows '_' while (bytes < end_bytes) { jchar c; bytes = UTF8::next(bytes, &c); if (c <= 0x7f && isalnum(c)) { + if (check_escape_char && (c >= '0' && c <= '3') && + !UseLegacyJNINameEscaping) { + // This is a non-Java identifier and we won't escape it to + // ensure no name collisions with a Java identifier. + if (PrintJNIResolving) { + ResourceMark rm; + tty->print_cr("[Lookup of native method with non-Java identifier rejected: %s]", + name->as_C_string()); + } + st->reset(); // restore to "" on error + return false; + } st->put((char) c); + check_escape_char = false; } else { - if (c == '_') st->print("_1"); - else if (c == '/') st->print("_"); + check_escape_char = false; + if (c == '_') st->print("_1"); + else if (c == '/') { + st->print("_"); + // Following a / we must have non-escape character + check_escape_char = true; + } else if (c == ';') st->print("_2"); else if (c == '[') st->print("_3"); else st->print("_%.5x", c); } } + return true; } -static void mangle_name_on(outputStream* st, Symbol* name) { - mangle_name_on(st, name, 0, name->utf8_length()); +static bool map_escaped_name_on(stringStream* st, Symbol* name) { + return map_escaped_name_on(st, name, 0, name->utf8_length()); } @@ -90,10 +181,14 @@ // Prefix st.print("Java_"); // Klass name - mangle_name_on(&st, method->klass_name()); + if (!map_escaped_name_on(&st, method->klass_name())) { + return NULL; + } st.print("_"); // Method name - mangle_name_on(&st, method->name()); + if (!map_escaped_name_on(&st, method->name())) { + return NULL; + } return st.as_string(); } @@ -103,16 +198,20 @@ // Prefix st.print("JavaCritical_"); // Klass name - mangle_name_on(&st, method->klass_name()); + if (!map_escaped_name_on(&st, method->klass_name())) { + return NULL; + } st.print("_"); // Method name - mangle_name_on(&st, method->name()); + if (!map_escaped_name_on(&st, method->name())) { + return NULL; + } return st.as_string(); } char* NativeLookup::long_jni_name(methodHandle method) { - // Signature ignore the wrapping parenteses and the trailing return type + // Signatures ignore the wrapping parentheses and the trailing return type stringStream st; Symbol* signature = method->signature(); st.print("__"); @@ -120,7 +219,10 @@ int end; for (end = 0; end < signature->utf8_length() && signature->byte_at(end) != ')'; end++); // skip first '(' - mangle_name_on(&st, signature, 1, end); + if (!map_escaped_name_on(&st, signature, 1, end)) { + return NULL; + } + return st.as_string(); } @@ -247,6 +349,11 @@ in_base_library = false; // Compute pure name char* pure_name = pure_jni_name(method); + if (pure_name == NULL) { + // JNI name mapping rejected this method so return + // NULL to indicate UnsatisfiedLinkError should be thrown. + return NULL; + } // Compute argument size int args_size = 1 // JNIEnv @@ -260,6 +367,11 @@ // Compute long name char* long_name = long_jni_name(method); + if (long_name == NULL) { + // JNI name mapping rejected this method so return + // NULL to indicate UnsatisfiedLinkError should be thrown. + return NULL; + } // 2) Try JNI long style entry = lookup_style(method, pure_name, long_name, args_size, true, in_base_library, CHECK_NULL); @@ -299,6 +411,11 @@ // Compute critical name char* critical_name = critical_jni_name(method); + if (critical_name == NULL) { + // JNI name mapping rejected this method so return + // NULL to indicate UnsatisfiedLinkError should be thrown. + return NULL; + } // Compute argument size int args_size = 1 // JNIEnv @@ -312,6 +429,11 @@ // Compute long name char* long_name = long_jni_name(method); + if (long_name == NULL) { + // JNI name mapping rejected this method so return + // NULL to indicate UnsatisfiedLinkError should be thrown. + return NULL; + } // 2) Try JNI long style entry = lookup_critical_style(method, critical_name, long_name, args_size, true);
--- a/src/share/vm/runtime/globals.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/runtime/globals.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -718,6 +718,9 @@ product(bool, CriticalJNINatives, true, \ "Check for critical JNI entry points") \ \ + product(bool, UseLegacyJNINameEscaping, false, \ + "Use the original JNI name escaping scheme") \ + \ notproduct(bool, StressCriticalJNINatives, false, \ "Exercise register saving code in critical natives") \ \ @@ -1351,7 +1354,7 @@ develop(bool, TraceClassInitialization, false, \ "Trace class initialization") \ \ - develop(bool, TraceExceptions, false, \ + product(bool, TraceExceptions, false, \ "Trace exceptions") \ \ develop(bool, TraceICs, false, \ @@ -2031,7 +2034,7 @@ experimental(uintx, WorkStealingSpinToYieldRatio, 10, \ "Ratio of hard spins to calls to yield") \ \ - develop(uintx, ObjArrayMarkingStride, 512, \ + develop(uintx, ObjArrayMarkingStride, 2048, \ "Number of object array elements to push onto the marking stack " \ "before pushing a continuation entry") \ \
--- a/src/share/vm/runtime/reflection.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/runtime/reflection.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -506,7 +506,7 @@ (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION && accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) { return classloader_only && - Verifier::relax_access_for(accessor_ik->class_loader()) && + Verifier::relax_verify_for(accessor_ik->class_loader()) && accessor_ik->protection_domain() == accessee_ik->protection_domain() && accessor_ik->class_loader() == accessee_ik->class_loader(); } else {
--- a/src/share/vm/runtime/thread.cpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/runtime/thread.cpp Tue Oct 27 06:33:36 2020 +0000 @@ -3440,7 +3440,7 @@ return status; } - JFR_ONLY(Jfr::on_create_vm_1();) + JFR_ONLY(Jfr::on_vm_init();) // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3491,16 +3491,12 @@ ShouldNotReachHere(); } -#if !INCLUDE_JFR - // if JFR is not enabled at the build time keep the original JvmtiExport location - // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution JvmtiExport::enter_start_phase(); // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. JvmtiExport::post_vm_start(); -#endif { TraceTime timer("Initialize java.lang classes", TraceStartupTime); @@ -3547,19 +3543,6 @@ initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); } - JFR_ONLY( - Jfr::on_create_vm_2(); - - // if JFR is enabled at build time the JVMTI needs to be handled only after on_create_vm_2() call - - // Always call even when there are not JVMTI environments yet, since environments - // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_start_phase(); - - // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. - JvmtiExport::post_vm_start(); - ) - // See : bugid 4211085. // Background : the static initializer of java.lang.Compiler tries to read // property"java.compiler" and read & write property "java.vm.info". @@ -3654,7 +3637,7 @@ // Notify JVMTI agents that VM initialization is complete - nop if no agents. JvmtiExport::post_vm_initialized(); - JFR_ONLY(Jfr::on_create_vm_3();) + JFR_ONLY(Jfr::on_vm_start();) if (CleanChunkPoolAsync) { Chunk::start_chunk_pool_cleaner_task();
--- a/src/share/vm/utilities/globalDefinitions.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/utilities/globalDefinitions.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -1066,6 +1066,7 @@ const intptr_t badAddressVal = -2; // generic "bad address" value const intptr_t badOopVal = -1; // generic "bad oop" value const intptr_t badHeapOopVal = (intptr_t) CONST64(0x2BAD4B0BBAADBABE); // value used to zap heap after GC +const int badStackSegVal = 0xCA; // value used to zap stack segments const int badHandleValue = 0xBC; // value used to zap vm handle area const int badResourceValue = 0xAB; // value used to zap resource area const int freeBlockPad = 0xBA; // value used to pad freed blocks.
--- a/src/share/vm/utilities/stack.inline.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/utilities/stack.inline.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -26,6 +26,7 @@ #define SHARE_VM_UTILITIES_STACK_INLINE_HPP #include "utilities/stack.hpp" +#include "utilities/copy.hpp" template <MEMFLAGS F> StackBase<F>::StackBase(size_t segment_size, size_t max_cache_size, size_t max_size): @@ -227,11 +228,7 @@ { if (!ZapStackSegments) return; const size_t zap_bytes = segment_bytes() - (zap_link_field ? 0 : sizeof(E*)); - uint32_t* cur = (uint32_t*)seg; - const uint32_t* end = cur + zap_bytes / sizeof(uint32_t); - while (cur < end) { - *cur++ = 0xfadfaded; - } + Copy::fill_to_bytes(seg, zap_bytes, badStackSegVal); } #endif
--- a/src/share/vm/utilities/taskqueue.hpp Tue Oct 27 03:35:20 2020 +0000 +++ b/src/share/vm/utilities/taskqueue.hpp Tue Oct 27 06:33:36 2020 +0000 @@ -332,7 +332,8 @@ // index, &_elems[index], _elems[index]); E* t = (E*)&_elems[index]; // cast away volatility oop* p = (oop*)t; - assert((*t)->is_oop_or_null(), "Not an oop or null"); + // G1 does its own checking + assert(UseG1GC || (*t)->is_oop_or_null(), "Not an oop or null"); f->do_oop(p); } // tty->print_cr("END OopTaskQueue::oops_do");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/types/TestArrayMeetNotSymmetrical.java Tue Oct 27 06:33:36 2020 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, Red Hat, Inc. 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 8240676 + * @summary Meet not symmetric failure when running lucene on jdk8 + * + * @run main/othervm -XX:-BackgroundCompilation TestArrayMeetNotSymmetrical + * + */ + +public class TestArrayMeetNotSymmetrical { + private static final Object field = new Object[0]; + private static final Object field2 = new A[0]; + + public static void main(String[] args) { + Object array = new A[10]; + for (int i = 0; i < 20_000; i++) { + test1(true, 10); + test1(false, 10); + test2(true); + test2(false); + } + } + + private static Object test1(boolean flag, int len) { + Object o; + if (flag) { + o = field; + } else { + o = new A[len]; + } + return o; + } + + private static Object test2(boolean flag) { + Object o; + if (flag) { + o = field; + } else { + o = field2; + } + return o; + } + + + private static class A { + } +}
--- a/test/runtime/8233197/T.java Tue Oct 27 03:35:20 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -public class T -{ - public static void main(String[] args) throws Exception - { - for (int i = 0; i < 50; i++) { - System.out.print("+"); - Thread.sleep(1); - } - System.out.println(); - } -}
--- a/test/runtime/8233197/Test8233197.sh Tue Oct 27 03:35:20 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2013, 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 Test8233197.sh -## @bug 8233197 -## @summary Check that JFR subsystem can be initialized from VMStart JVMTI event -## @compile T.java -## @run shell Test8233197.sh -## - -set -x -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 -OS=`uname -s` -case "$OS" in - Linux) - gcc_cmd=`which gcc` - if [ "x$gcc_cmd" == "x" ]; then - echo "WARNING: gcc not found. Cannot execute test." 2>&1 - exit 0; - fi - NULL=/dev/null - PS=":" - FS="/" - ;; - * ) - echo "Test passed; only valid for Linux" - exit 0; - ;; -esac - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 - -# Bitness: -# Cannot simply look at TESTVMOPTS as -d64 is not -# passed if there is only a 64-bit JVM available. - -grep "64-Bit" vm_version.out > ${NULL} -if [ "$?" = "0" ] -then - COMP_FLAG="-m64" -else - COMP_FLAG="-m32" -fi - - -# Architecture: -# Translate uname output to JVM directory name, but permit testing -# 32-bit x86 on an x64 platform. -ARCH=`uname -m` -case "$ARCH" in - x86_64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=i386 - else - ARCH=amd64 - fi - ;; - ppc64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=ppc - else - ARCH=ppc64 - fi - ;; - sparc64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=sparc - else - ARCH=sparc64 - fi - ;; - arm*) - # 32-bit ARM machine: compiler may not recognise -m32 - COMP_FLAG="" - ARCH=arm - ;; - aarch64) - # 64-bit arm machine, could be testing 32 or 64-bit: - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=arm - else - ARCH=aarch64 - fi - ;; - i586) - ARCH=i386 - ;; - i686) - ARCH=i386 - ;; - # Assuming other ARCH values need no translation -esac - - -# VM type: need to know server or client -VMTYPE=client -grep Server vm_version.out > ${NULL} -if [ "$?" = "0" ] -then - VMTYPE=server -fi - - -LD_LIBRARY_PATH=.:${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH -export LD_LIBRARY_PATH - -cp ${TESTSRC}${FS}libJvmtiAgent.c . - -# Copy the result of our @compile action: -cp ${TESTCLASSES}${FS}T.class . - -echo "Architecture: ${ARCH}" -echo "Compilation flag: ${COMP_FLAG}" -echo "VM type: ${VMTYPE}" - -$gcc_cmd -DLINUX ${COMP_FLAG} -Wl, -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -c -o libJvmtiAgent.o \ - -I${COMPILEJAVA}/include -I${COMPILEJAVA}/include/linux \ - -L${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE} \ - libJvmtiAgent.c -$gcc_cmd -shared -o libJvmtiAgent.so libJvmtiAgent.o - -"$TESTJAVA/bin/java" $TESTVMOPTS -agentlib:JvmtiAgent -cp $(pwd) T > T.out -exit $? \ No newline at end of file
--- a/test/runtime/8233197/libJvmtiAgent.c Tue Oct 27 03:35:20 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2017, 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "jvmti.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef JNI_ENV_ARG - -#ifdef __cplusplus -#define JNI_ENV_ARG(x, y) y -#define JNI_ENV_PTR(x) x -#else -#define JNI_ENV_ARG(x,y) x, y -#define JNI_ENV_PTR(x) (*x) -#endif - -#endif - -#define TranslateError(err) "JVMTI error" - -static jvmtiEnv *jvmti = NULL; - -static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); - -JNIEXPORT -jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT -jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT -jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { - return JNI_VERSION_1_8; -} - -static void JNICALL -Callback_VMStart(jvmtiEnv *jvmti_env, JNIEnv *env) { - printf("Localizing jdk.jfr.FlightRecorder\n"); - // without fix for 8233197 the process will crash at the following line - jclass cls = (*env)->FindClass(env, "jdk/jfr/FlightRecorder"); - jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getFlightRecorder", "()Ljdk/jfr/FlightRecorder;"); - if (mid == 0) { - printf("Unable to localize jdk.jfr.FlightRecorder#getFlightRecorder() method\n"); - // crash the tested JVM to make the test fail - exit(-1); - } - printf("Going to initialize JFR subsystem ...\n"); - jobject jfr = (*env)->CallStaticObjectMethod(env, cls, mid); - - if (!(*env)->ExceptionCheck(env)) { - // crash the tested JVM to make the test fail - printf("JFR subsystem is wrongly initialized too early\n"); - exit(-2); - } - // exit VM - exit(0); -} - -static -jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { - jint res, size; - jvmtiCapabilities caps; - jvmtiEventCallbacks callbacks; - jvmtiError err; - - res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), - JVMTI_VERSION_1_2); - if (res != JNI_OK || jvmti == NULL) { - printf(" Error: wrong result of a valid call to GetEnv!\n"); - return JNI_ERR; - } - - size = (jint)sizeof(callbacks); - - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.VMStart = Callback_VMStart; - - err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); - if (err != JVMTI_ERROR_NONE) { - printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err); - return JNI_ERR; - } - - err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL); - if (err != JVMTI_ERROR_NONE) { - printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err); - return JNI_ERR; - } - return JNI_OK; -} - -#ifdef __cplusplus -} -#endif
--- a/test/runtime/ClassFile/BadHelloWorld.jcod Tue Oct 27 03:35:20 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -/* - * 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. - */ - -/* - * This file fuzzes the class name #15 to have a leading 'L' and ending ';'. - */ - -class BadHelloWorld { - 0xCAFEBABE; - 0; // minor version - 52; // version - [31] { // Constant Pool - ; // first element is empty - Utf8 "BadHelloWorld"; // #1 at 0x0A - class #1; // #2 at 0x1A - Utf8 "java/lang/Object"; // #3 at 0x1D - class #3; // #4 at 0x30 - Utf8 "<init>"; // #5 at 0x33 - Utf8 "()V"; // #6 at 0x3C - NameAndType #5 #6; // #7 at 0x42 - Method #4 #7; // #8 at 0x47 - Utf8 "toString"; // #9 at 0x4C - Utf8 "()Ljava/lang/String;"; // #10 at 0x57 - Utf8 "Hello, world!"; // #11 at 0x6E - String #11; // #12 at 0x7E - Utf8 "main"; // #13 at 0x81 - Utf8 "([Ljava/lang/String;)V"; // #14 at 0x88 - Utf8 "LBadHelloWorld;"; // #15 at 0xA1 - class #15; // #16 at 0xB3 - Method #16 #7; // #17 at 0xB6 - Utf8 "java/lang/System"; // #18 at 0xBB - class #18; // #19 at 0xCE - Utf8 "out"; // #20 at 0xD1 - Utf8 "Ljava/io/PrintStream;"; // #21 at 0xD7 - NameAndType #20 #21; // #22 at 0xEF - Field #19 #22; // #23 at 0xF4 - Utf8 "java/io/PrintStream"; // #24 at 0xF9 - class #24; // #25 at 0x010F - Utf8 "println"; // #26 at 0x0112 - Utf8 "(Ljava/lang/Object;)V"; // #27 at 0x011C - NameAndType #26 #27; // #28 at 0x0134 - Method #25 #28; // #29 at 0x0139 - Utf8 "Code"; // #30 at 0x013E - } // Constant Pool - - 0x0021; // access - #2;// this_cpx - #4;// super_cpx - - [0] { // Interfaces - } // Interfaces - - [0] { // fields - } // fields - - [3] { // methods - { // Member at 0x0151 - 0x0001; // access - #5; // name_cpx - #6; // sig_cpx - [1] { // Attributes - Attr(#30, 17) { // Code at 0x0159 - 1; // max_stack - 1; // max_locals - Bytes[5]{ - 0x2AB70008B1; - }; - [0] { // Traps - } // end Traps - [0] { // Attributes - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x0170 - 0x0001; // access - #9; // name_cpx - #10; // sig_cpx - [1] { // Attributes - Attr(#30, 15) { // Code at 0x0178 - 1; // max_stack - 1; // max_locals - Bytes[3]{ - 0x120CB0; - }; - [0] { // Traps - } // end Traps - [0] { // Attributes - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x018D - 0x0089; // access - #13; // name_cpx - #14; // sig_cpx - [1] { // Attributes - Attr(#30, 28) { // Code at 0x0195 - 2; // max_stack - 2; // max_locals - Bytes[16]{ - 0xBB001059B700114C; - 0xB200172BB6001DB1; - }; - [0] { // Traps - } // end Traps - [0] { // Attributes - } // Attributes - } // end Code - } // Attributes - } // Member - } // methods - - [0] { // Attributes - } // Attributes -} // end class BadHelloWorld
--- a/test/runtime/ClassFile/FormatCheckingTest.java Tue Oct 27 03:35:20 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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 8148854 - * @summary Ensure class name loaded by app class loader is format checked by default - * @library /testlibrary - * @compile BadHelloWorld.jcod - * @run main FormatCheckingTest - */ - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - -public class FormatCheckingTest { - public static void main(String args[]) throws Throwable { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("BadHelloWorld"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("java.lang.ClassFormatError: Illegal class name"); - output.shouldHaveExitValue(1); - } -}
--- a/test/runtime/CommandLine/TraceExceptionsTest.java Tue Oct 27 03:35:20 2020 +0000 +++ b/test/runtime/CommandLine/TraceExceptionsTest.java Tue Oct 27 06:33:36 2020 +0000 @@ -33,11 +33,6 @@ public class TraceExceptionsTest { public static void main(String[] args) throws Exception { - if (!Platform.isDebugBuild()) { - System.out.println("Skip the test on product builds since XX:+TraceExceptions is not available on product builds"); - return; - } - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+TraceExceptions", "NoClassFound"); OutputAnalyzer output = new OutputAnalyzer(pb.start());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/containers/docker/CheckOperatingSystemMXBean.java Tue Oct 27 06:33:36 2020 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Red Hat Inc. 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 com.sun.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; + +public class CheckOperatingSystemMXBean { + + public static void main(String[] args) { + System.out.println("Checking OperatingSystemMXBean"); + + OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + System.out.println(String.format("Runtime.availableProcessors: %d", Runtime.getRuntime().availableProcessors())); + System.out.println(String.format("OperatingSystemMXBean.getAvailableProcessors: %d", osBean.getAvailableProcessors())); + System.out.println(String.format("OperatingSystemMXBean.getTotalPhysicalMemorySize: %d", osBean.getTotalPhysicalMemorySize())); + System.out.println(String.format("OperatingSystemMXBean.getFreePhysicalMemorySize: %d", osBean.getFreePhysicalMemorySize())); + System.out.println(String.format("OperatingSystemMXBean.getTotalSwapSpaceSize: %d", osBean.getTotalSwapSpaceSize())); + System.out.println(String.format("OperatingSystemMXBean.getFreeSwapSpaceSize: %d", osBean.getFreeSwapSpaceSize())); + System.out.println(String.format("OperatingSystemMXBean.getSystemCpuLoad: %f", osBean.getSystemCpuLoad())); + } + +}
--- a/test/runtime/containers/docker/Dockerfile-BasicTest Tue Oct 27 03:35:20 2020 +0000 +++ b/test/runtime/containers/docker/Dockerfile-BasicTest Tue Oct 27 06:33:36 2020 +0000 @@ -1,4 +1,4 @@ -FROM oraclelinux:7.2 +FROM oraclelinux:7.6 MAINTAINER mikhailo.seledtsov@oracle.com COPY /jdk /jdk
--- a/test/runtime/containers/docker/TestCPUAwareness.java Tue Oct 27 03:35:20 2020 +0000 +++ b/test/runtime/containers/docker/TestCPUAwareness.java Tue Oct 27 06:33:36 2020 +0000 @@ -25,7 +25,9 @@ /* * @test * @summary Test JVM's CPU resource awareness when running inside docker container - * @library /testlibrary + * @library /testlibrary /testlibrary/whitebox + * @build sun.hotspot.WhiteBox PrintContainerInfo CheckOperatingSystemMXBean + * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver TestCPUAwareness */ @@ -72,6 +74,14 @@ testCpuQuotaAndPeriod(150*1000, 100*1000); testCpuQuotaAndPeriod(400*1000, 100*1000); + testOperatingSystemMXBeanAwareness("0.5", "1"); + testOperatingSystemMXBeanAwareness("1.0", "1"); + if (availableCPUs > 2) { + testOperatingSystemMXBeanAwareness("1.2", "2"); + testOperatingSystemMXBeanAwareness("1.8", "2"); + testOperatingSystemMXBeanAwareness("2.0", "2"); + } + } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -202,4 +212,21 @@ .shouldMatch("CPU Shares is.*" + shares) .shouldMatch("active_processor_count.*" + expectedAPC); } + + private static void testOperatingSystemMXBeanAwareness(String cpuAllocation, String expectedCpus) throws Exception { + Common.logNewTestCase("Check OperatingSystemMXBean"); + + DockerRunOptions opts = Common.newOpts(imageName, "CheckOperatingSystemMXBean") + .addDockerOpts( + "--cpus", cpuAllocation + ); + + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain("Checking OperatingSystemMXBean") + .shouldContain("Runtime.availableProcessors: " + expectedCpus) + .shouldContain("OperatingSystemMXBean.getAvailableProcessors: " + expectedCpus) + .shouldMatch("OperatingSystemMXBean\\.getSystemCpuLoad: [0-9]+\\.[0-9]+") + ; + } }
--- a/test/runtime/containers/docker/TestMemoryAwareness.java Tue Oct 27 03:35:20 2020 +0000 +++ b/test/runtime/containers/docker/TestMemoryAwareness.java Tue Oct 27 06:33:36 2020 +0000 @@ -26,7 +26,7 @@ * @test * @summary Test JVM's memory resource awareness when running inside docker container * @library /testlibrary /testlibrary/whitebox - * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo + * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo CheckOperatingSystemMXBean * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver TestMemoryAwareness */ @@ -59,6 +59,18 @@ // Add extra 10 Mb to allocator limit, to be sure to cause OOM testOOM("256m", 256 + 10); + testOperatingSystemMXBeanAwareness( + "100M", Integer.toString(((int) Math.pow(2, 20)) * 100), + "150M", Integer.toString(((int) Math.pow(2, 20)) * (150 - 100)) + ); + testOperatingSystemMXBeanAwareness( + "128M", Integer.toString(((int) Math.pow(2, 20)) * 128), + "256M", Integer.toString(((int) Math.pow(2, 20)) * (256 - 128)) + ); + testOperatingSystemMXBeanAwareness( + "1G", Integer.toString(((int) Math.pow(2, 20)) * 1024), + "1500M", Integer.toString(((int) Math.pow(2, 20)) * (1500 - 1024)) + ); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -106,4 +118,24 @@ .shouldContain("java.lang.OutOfMemoryError"); } + private static void testOperatingSystemMXBeanAwareness(String memoryAllocation, String expectedMemory, + String swapAllocation, String expectedSwap) throws Exception { + Common.logNewTestCase("Check OperatingSystemMXBean"); + + DockerRunOptions opts = Common.newOpts(imageName, "CheckOperatingSystemMXBean") + .addDockerOpts( + "--memory", memoryAllocation, + "--memory-swap", swapAllocation + ); + + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain("Checking OperatingSystemMXBean") + .shouldContain("OperatingSystemMXBean.getTotalPhysicalMemorySize: " + expectedMemory) + .shouldMatch("OperatingSystemMXBean\\.getFreePhysicalMemorySize: [1-9][0-9]+") + .shouldContain("OperatingSystemMXBean.getTotalSwapSpaceSize: " + expectedSwap) + .shouldMatch("OperatingSystemMXBean\\.getFreeSwapSpaceSize: [1-9][0-9]+") + ; + } + }