Mercurial > hg > icedtea8-forest > hotspot
changeset 9703:c14f056eed68 icedtea-3.7.0pre01
Merge jdk8u152-b16
line wrap: on
line diff
--- a/.hgtags Thu Nov 02 06:16:13 2017 +0000 +++ b/.hgtags Thu Dec 07 02:46:58 2017 +0000 @@ -1036,3 +1036,30 @@ e352e54382928eb8d5ec70455ef251973c332ccb jdk8u151-b10 0f06584f52ffc8627b78f4d461a3eba2b703a8f7 jdk8u151-b11 9bad7d4825fb14efb65fc7bad625bbeaf135339e icedtea-3.6.0 +856e341587d52114a753e48674517e7e307fceff jdk8u151-b12 +5aa8c4ca51f0e666d368a4f119ed734d3ac59d7c jdk8u122-b00 +2198ef7e1c1702b3506b95b5d8c886ad5a12bbe5 jdk8u122-b01 +58d961f47dd4ee1d516512b7744e0f1fc83d8f52 jdk8u122-b02 +b0f2296a0bc85e400e4389306219fcfd2076c9b5 jdk8u122-b03 +b0f2296a0bc85e400e4389306219fcfd2076c9b5 jdk8u122-b03 +0000000000000000000000000000000000000000 jdk8u122-b03 +0000000000000000000000000000000000000000 jdk8u122-b03 +65601f3eae818a49a5246c73fb4872f5467a230c jdk8u122-b03 +fb8ea28efb05cd89e5416665232165ef0d2eef29 jdk8u122-b04 +92aff007ba7fd9b69adcf212c5280b9152f3d667 jdk8u132-b00 +8cc092b845ce5dae4fa450d23d8bb9abf509e1a0 jdk8u152-b00 +77d9c9da7188ef4d5fe9c409362d63911c4794e8 jdk8u152-b01 +60d621df6c586e325c0a2cf045c8fc68b7f979fe jdk8u152-b02 +d63e731a896c711b8e0c30ac9ae2d900d4e024f6 jdk8u152-b03 +0bd600d6d77b5b41780074bcbfa133032dadf657 jdk8u152-b04 +68758c5ab0c1ef01e89bea8a9b799714831a177f jdk8u152-b05 +98fb3d75fe567bda30a3667c58a9f83ad2acbdf3 jdk8u152-b06 +4af38194b12580bdc885ab3873d7efefa990f543 jdk8u152-b07 +285fcd09ae9994ac836a2759f6615520b2568432 jdk8u152-b08 +70f18ab733f55856cbd880fe8ba3034ff4d7265d jdk8u152-b09 +39967c81d3f3b8d20584d1400e6f4b2490f0c822 jdk8u152-b10 +cbb6bc4b8c867ea69962fd5b6c79ffe3aa9fd77d jdk8u152-b11 +cdfe7ec6f29293d7c2f64239518e8947733ad85c jdk8u152-b12 +3dd92151df1b3b7c21756f241b49607024b6fe5a jdk8u152-b13 +0a9d8db98fc5f0302da6520ba329f41baa092ae0 jdk8u152-b14 +c1bf165d3b27e864a9f8eec5bb0c1e746a972ad5 jdk8u152-b15
--- a/ASSEMBLY_EXCEPTION Thu Nov 02 06:16:13 2017 +0000 +++ b/ASSEMBLY_EXCEPTION Thu Dec 07 02:46:58 2017 +0000 @@ -1,9 +1,9 @@ OPENJDK ASSEMBLY EXCEPTION -The OpenJDK source code made available by Oracle at openjdk.java.net and -openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the -GNU General Public License <http://www.gnu.org/copyleft/gpl.html> version 2 +The OpenJDK source code made available by Oracle America, Inc. (Oracle) at +openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU +General Public License <http://www.gnu.org/copyleft/gpl.html> version 2 only ("GPL2"), with the following clarification and special exception. Linking this OpenJDK Code statically or dynamically with other code @@ -19,9 +19,9 @@ provided that the Designated Exception Modules continue to be governed by the licenses under which they were offered by Oracle. -As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code to -build an executable that includes those portions of necessary code that Oracle -could not provide under GPL2 (or that Oracle has provided under GPL2 with the -Classpath exception). If you modify or add to the OpenJDK code, that new -GPL2 code may still be combined with Designated Exception Modules if the -new code is made subject to this exception by its copyright holder. +As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code +to build an executable that includes those portions of necessary code that +Oracle could not provide under GPL2 (or that Oracle has provided under GPL2 +with the Classpath exception). If you modify or add to the OpenJDK code, +that new GPL2 code may still be combined with Designated Exception Modules +if the new code is made subject to this exception by its copyright holder.
--- a/src/cpu/ppc/vm/assembler_ppc.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/assembler_ppc.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -589,6 +589,7 @@ VNOR_OPCODE = (4u << OPCODE_SHIFT | 1284u ), VOR_OPCODE = (4u << OPCODE_SHIFT | 1156u ), VXOR_OPCODE = (4u << OPCODE_SHIFT | 1220u ), + VRLD_OPCODE = (4u << OPCODE_SHIFT | 196u ), VRLB_OPCODE = (4u << OPCODE_SHIFT | 4u ), VRLW_OPCODE = (4u << OPCODE_SHIFT | 132u ), VRLH_OPCODE = (4u << OPCODE_SHIFT | 68u ), @@ -1920,6 +1921,7 @@ inline void vnor( VectorRegister d, VectorRegister a, VectorRegister b); inline void vor( VectorRegister d, VectorRegister a, VectorRegister b); inline void vxor( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vrld( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlb( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vrlh( VectorRegister d, VectorRegister a, VectorRegister b);
--- a/src/cpu/ppc/vm/assembler_ppc.inline.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/assembler_ppc.inline.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -741,6 +741,7 @@ inline void Assembler::vnor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VNOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vxor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VXOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vrld( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlb( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vrlh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VRLH_OPCODE | vrt(d) | vra(a) | vrb(b)); }
--- a/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -62,7 +62,7 @@ nativeMovConstReg_at(addr())->set_narrow_oop(no, code()); } } else { - assert((address) (nativeMovConstReg_at(addr())->data()) == x, "data must match"); + guarantee((address) (nativeMovConstReg_at(addr())->data()) == x, "data must match"); } }
--- a/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1961,6 +1961,434 @@ return start; } + // Arguments for generated stub (little endian only): + // R3_ARG1 - source byte array address + // R4_ARG2 - destination byte array address + // R5_ARG3 - round key array + address generate_aescrypt_encryptBlock() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock"); + + address start = __ function_entry(); + + Label L_doLast; + + Register from = R3_ARG1; // source array address + Register to = R4_ARG2; // destination array address + Register key = R5_ARG3; // round key array + + Register keylen = R8; + Register temp = R9; + Register keypos = R10; + Register hex = R11; + Register fifteen = R12; + + VectorRegister vRet = VR0; + + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + + VectorRegister fromPerm = VR5; + VectorRegister keyPerm = VR6; + VectorRegister toPerm = VR7; + VectorRegister fSplt = VR8; + + VectorRegister vTmp1 = VR9; + VectorRegister vTmp2 = VR10; + VectorRegister vTmp3 = VR11; + VectorRegister vTmp4 = VR12; + + VectorRegister vLow = VR13; + VectorRegister vHigh = VR14; + + __ li (hex, 16); + __ li (fifteen, 15); + __ vspltisb (fSplt, 0x0f); + + // load unaligned from[0-15] to vsRet + __ lvx (vRet, from); + __ lvx (vTmp1, fifteen, from); + __ lvsl (fromPerm, from); + __ vxor (fromPerm, fromPerm, fSplt); + __ vperm (vRet, vRet, vTmp1, fromPerm); + + // load keylen (44 or 52 or 60) + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); + + // to load keys + __ lvsr (keyPerm, key); + __ vxor (vTmp2, vTmp2, vTmp2); + __ vspltisb (vTmp2, -16); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vsldoi (keyPerm, keyPerm, keyPerm, -8); + + // load the 1st round key to vKey1 + __ li (keypos, 0); + __ lvx (vKey1, keypos, key); + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey1, vTmp1, vKey1, keyPerm); + + // 1st round + __ vxor (vRet, vRet, vKey1); + + // load the 2nd round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 3rd round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 4th round key to vKey3 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 5th round key to vKey4 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // 2nd - 5th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // load the 6th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 7th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 8th round key to vKey3 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 9th round key to vKey4 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // 6th - 9th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // load the 10th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // if all round keys are loaded, skip next 4 rounds + __ cmpwi (CCR0, keylen, 44); + __ beq (CCR0, L_doLast); + + // 10th - 11th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // load the 12th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 13th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // if all round keys are loaded, skip next 2 rounds + __ cmpwi (CCR0, keylen, 52); + __ beq (CCR0, L_doLast); + + // 12th - 13th rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // load the 14th round key to vKey1 + __ addi (keypos, keypos, 16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 15th round key to vKey2 + __ addi (keypos, keypos, 16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + __ bind(L_doLast); + + // last two rounds + __ vcipher (vRet, vRet, vKey1); + __ vcipherlast (vRet, vRet, vKey2); + + __ neg (temp, to); + __ lvsr (toPerm, temp); + __ vspltisb (vTmp2, -1); + __ vxor (vTmp1, vTmp1, vTmp1); + __ vperm (vTmp2, vTmp2, vTmp1, toPerm); + __ vxor (toPerm, toPerm, fSplt); + __ lvx (vTmp1, to); + __ vperm (vRet, vRet, vRet, toPerm); + __ vsel (vTmp1, vTmp1, vRet, vTmp2); + __ lvx (vTmp4, fifteen, to); + __ stvx (vTmp1, to); + __ vsel (vRet, vRet, vTmp4, vTmp2); + __ stvx (vRet, fifteen, to); + + __ blr(); + return start; + } + + // Arguments for generated stub (little endian only): + // R3_ARG1 - source byte array address + // R4_ARG2 - destination byte array address + // R5_ARG3 - K (key) in little endian int array + address generate_aescrypt_decryptBlock() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock"); + + address start = __ function_entry(); + + Label L_doLast; + Label L_do44; + Label L_do52; + Label L_do60; + + Register from = R3_ARG1; // source array address + Register to = R4_ARG2; // destination array address + Register key = R5_ARG3; // round key array + + Register keylen = R8; + Register temp = R9; + Register keypos = R10; + Register hex = R11; + Register fifteen = R12; + + VectorRegister vRet = VR0; + + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + VectorRegister vKey5 = VR5; + + VectorRegister fromPerm = VR6; + VectorRegister keyPerm = VR7; + VectorRegister toPerm = VR8; + VectorRegister fSplt = VR9; + + VectorRegister vTmp1 = VR10; + VectorRegister vTmp2 = VR11; + VectorRegister vTmp3 = VR12; + VectorRegister vTmp4 = VR13; + + VectorRegister vLow = VR14; + VectorRegister vHigh = VR15; + + __ li (hex, 16); + __ li (fifteen, 15); + __ vspltisb (fSplt, 0x0f); + + // load unaligned from[0-15] to vsRet + __ lvx (vRet, from); + __ lvx (vTmp1, fifteen, from); + __ lvsl (fromPerm, from); + __ vxor (fromPerm, fromPerm, fSplt); + __ vperm (vRet, vRet, vTmp1, fromPerm); // align [and byte swap in LE] + + // load keylen (44 or 52 or 60) + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); + + // to load keys + __ lvsr (keyPerm, key); + __ vxor (vTmp2, vTmp2, vTmp2); + __ vspltisb (vTmp2, -16); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vrld (keyPerm, keyPerm, vTmp2); + __ vsldoi (keyPerm, keyPerm, keyPerm, -8); + + __ cmpwi (CCR0, keylen, 44); + __ beq (CCR0, L_do44); + + __ cmpwi (CCR0, keylen, 52); + __ beq (CCR0, L_do52); + + // load the 15th round key to vKey11 + __ li (keypos, 240); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 14th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 13th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // load the 12th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + + // 1st - 5th rounds + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + + __ b (L_doLast); + + __ bind (L_do52); + + // load the 13th round key to vKey11 + __ li (keypos, 208); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 12th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 11th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // 1st - 3rd rounds + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + + __ b (L_doLast); + + __ bind (L_do44); + + // load the 11th round key to vKey11 + __ li (keypos, 176); + __ lvx (vTmp1, keypos, key); + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // 1st round + __ vxor (vRet, vRet, vKey1); + + __ bind (L_doLast); + + // load the 10th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey1, vTmp2, vTmp1, keyPerm); + + // load the 9th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey2, vTmp1, vTmp2, keyPerm); + + // load the 8th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey3, vTmp2, vTmp1, keyPerm); + + // load the 7th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey4, vTmp1, vTmp2, keyPerm); + + // load the 6th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey5, vTmp2, vTmp1, keyPerm); + + // last 10th - 6th rounds + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + + // load the 5th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey1, vTmp1, vTmp2, keyPerm); + + // load the 4th round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey2, vTmp2, vTmp1, keyPerm); + + // load the 3rd round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey3, vTmp1, vTmp2, keyPerm); + + // load the 2nd round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp1, keypos, key); + __ vperm (vKey4, vTmp2, vTmp1, keyPerm); + + // load the 1st round key to vKey10 + __ addi (keypos, keypos, -16); + __ lvx (vTmp2, keypos, key); + __ vperm (vKey5, vTmp1, vTmp2, keyPerm); + + // last 5th - 1th rounds + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipherlast (vRet, vRet, vKey5); + + __ neg (temp, to); + __ lvsr (toPerm, temp); + __ vspltisb (vTmp2, -1); + __ vxor (vTmp1, vTmp1, vTmp1); + __ vperm (vTmp2, vTmp2, vTmp1, toPerm); + __ vxor (toPerm, toPerm, fSplt); + __ lvx (vTmp1, to); + __ vperm (vRet, vRet, vRet, toPerm); + __ vsel (vTmp1, vTmp1, vRet, vTmp2); + __ lvx (vTmp4, fifteen, to); + __ stvx (vTmp1, to); + __ vsel (vRet, vRet, vTmp4, vTmp2); + __ stvx (vRet, fifteen, to); + + __ blr(); + return start; + } + void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of // the conjoint stubs use them. @@ -2083,10 +2511,6 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - if (UseAESIntrinsics) { - guarantee(!UseAESIntrinsics, "not yet implemented."); - } - // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, @@ -2094,6 +2518,12 @@ generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry, &StubRoutines::_safefetchN_fault_pc, &StubRoutines::_safefetchN_continuation_pc); + + if (UseAESIntrinsics) { + StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); + StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + } + if (UseMontgomeryMultiplyIntrinsic) { StubRoutines::_montgomeryMultiply = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply);
--- a/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -102,7 +102,7 @@ // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -111,7 +111,8 @@ (has_popcntb() ? " popcntb" : ""), (has_popcntw() ? " popcntw" : ""), (has_fcfids() ? " fcfids" : ""), - (has_vand() ? " vand" : "") + (has_vand() ? " vand" : ""), + (has_vcipher() ? " aes" : "") // Make sure number of %s matches num_features! ); _features_str = strdup(buf); @@ -156,6 +157,28 @@ } // The AES intrinsic stubs require AES instruction support. +#if defined(VM_LITTLE_ENDIAN) + if (has_vcipher()) { + if (FLAG_IS_DEFAULT(UseAES)) { + UseAES = true; + } + } else if (UseAES) { + if (!FLAG_IS_DEFAULT(UseAES)) + warning("AES instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseAES, false); + } + + if (UseAES && has_vcipher()) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + UseAESIntrinsics = true; + } + } else if (UseAESIntrinsics) { + if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + +#else if (UseAES) { warning("AES instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseAES, false); @@ -165,6 +188,7 @@ warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } +#endif if (UseSHA) { warning("SHA instructions are not available on this CPU"); @@ -463,6 +487,7 @@ a->popcntw(R7, R5); // code[7] -> popcntw a->fcfids(F3, F4); // code[8] -> fcfids a->vand(VR0, VR0, VR0); // code[9] -> vand + a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -506,6 +531,7 @@ if (code[feature_cntr++]) features |= popcntw_m; if (code[feature_cntr++]) features |= fcfids_m; if (code[feature_cntr++]) features |= vand_m; + if (code[feature_cntr++]) features |= vcipher_m; // Print the detection code. if (PrintAssembly) {
--- a/src/cpu/ppc/vm/vm_version_ppc.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/ppc/vm/vm_version_ppc.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -42,6 +42,7 @@ fcfids, vand, dcba, + vcipher, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -56,6 +57,7 @@ fcfids_m = (1 << fcfids ), vand_m = (1 << vand ), dcba_m = (1 << dcba ), + vcipher_m = (1 << vcipher), all_features_m = -1 }; static int _features; @@ -83,6 +85,7 @@ static bool has_fcfids() { return (_features & fcfids_m) != 0; } static bool has_vand() { return (_features & vand_m) != 0; } static bool has_dcba() { return (_features & dcba_m) != 0; } + static bool has_vcipher() { return (_features & vcipher_m) != 0; } static const char* cpu_features() { return _features_str; }
--- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -4261,6 +4261,7 @@ assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing"); Register end = count; int cache_line_size = VM_Version::prefetch_data_size(); + assert(cache_line_size > 0, "cache line size should be known for this code"); // Minimum count when BIS zeroing can be used since // it needs membar which is expensive. int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
--- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -64,7 +64,7 @@ masm.patchable_sethi(x, destreg); int len = buffer - masm.pc(); for (int i = 0; i < len; i++) { - assert(instaddr[i] == buffer[i], "instructions must match"); + guarantee(instaddr[i] == buffer[i], "instructions must match"); } }
--- a/src/cpu/sparc/vm/relocInfo_sparc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -83,7 +83,7 @@ inst &= ~Assembler::simm( -1, 13); inst |= Assembler::simm(simm13, 13); if (verify_only) { - assert(ip->long_at(0) == inst, "instructions must match"); + guarantee(ip->long_at(0) == inst, "instructions must match"); } else { ip->set_long_at(0, inst); } @@ -101,15 +101,15 @@ inst &= ~Assembler::hi22(-1); inst |= Assembler::hi22((intptr_t)np); if (verify_only) { - assert(ip->long_at(0) == inst, "instructions must match"); + guarantee(ip->long_at(0) == inst, "instructions must match"); } else { ip->set_long_at(0, inst); } inst2 = ip->long_at( NativeInstruction::nop_instruction_size ); guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op"); if (verify_only) { - assert(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np), - "instructions must match"); + guarantee(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np), + "instructions must match"); } else { ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np)); } @@ -126,7 +126,7 @@ inst |= Assembler::hi22((intptr_t)x); // (ignore offset; it doesn't play into the sethi) if (verify_only) { - assert(ip->long_at(0) == inst, "instructions must match"); + guarantee(ip->long_at(0) == inst, "instructions must match"); } else { ip->set_long_at(0, inst); }
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -74,7 +74,7 @@ AllocatePrefetchDistance = AllocatePrefetchStepSize; } - if (AllocatePrefetchStyle == 3 && !has_blk_init()) { + if (AllocatePrefetchStyle == 3 && (!has_blk_init() || cache_line_size <= 0)) { warning("BIS instructions are not available on this CPU"); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); } @@ -138,7 +138,7 @@ FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } if (is_niagara_plus()) { - if (has_blk_init() && UseTLAB && + if (has_blk_init() && (cache_line_size > 0) && UseTLAB && FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { // Use BIS instruction for TLAB allocation prefetch. FLAG_SET_ERGO(intx, AllocatePrefetchInstr, 1); @@ -236,7 +236,7 @@ assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_v9() ? ", v9" : (has_v8() ? ", v8" : "")), (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", vis1" : ""), @@ -249,6 +249,7 @@ (has_sha256() ? ", sha256" : ""), (has_sha512() ? ", sha512" : ""), (is_ultra3() ? ", ultra3" : ""), + (has_sparc5_instr() ? ", sparc5" : ""), (is_sun4v() ? ", sun4v" : ""), (is_niagara_plus() ? ", niagara_plus" : (is_niagara() ? ", niagara" : "")), (is_sparc64() ? ", sparc64" : ""), @@ -371,6 +372,7 @@ #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { + tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { @@ -454,9 +456,10 @@ unsigned int VM_Version::calc_parallel_worker_threads() { unsigned int result; - if (is_M_series()) { - // for now, use same gc thread calculation for M-series as for niagara-plus - // in future, we may want to tweak parameters for nof_parallel_worker_thread + if (is_M_series() || is_S_series()) { + // for now, use same gc thread calculation for M-series and S-series as for + // niagara-plus. In future, we may want to tweak parameters for + // nof_parallel_worker_thread result = nof_parallel_worker_threads(5, 16, 8); } else if (is_niagara_plus()) { result = nof_parallel_worker_threads(5, 16, 8); @@ -465,3 +468,37 @@ } return result; } + + +int VM_Version::parse_features(const char* implementation) { + int features = unknown_m; + // Convert to UPPER case before compare. + char* impl = os::strdup(implementation); + + for (int i = 0; impl[i] != 0; i++) + impl[i] = (char)toupper((uint)impl[i]); + + if (strstr(impl, "SPARC64") != NULL) { + features |= sparc64_family_m; + } else if (strstr(impl, "SPARC-M") != NULL) { + // M-series SPARC is based on T-series. + features |= (M_family_m | T_family_m); + } else if (strstr(impl, "SPARC-S") != NULL) { + // S-series SPARC is based on T-series. + features |= (S_family_m | T_family_m); + } else if (strstr(impl, "SPARC-T") != NULL) { + features |= T_family_m; + if (strstr(impl, "SPARC-T1") != NULL) { + features |= T1_model_m; + } + } else if (strstr(impl, "SUN4V-CPU") != NULL) { + // Generic or migration class LDOM + features |= T_family_m; + } else { +#ifndef PRODUCT + warning("Failed to parse CPU implementation = '%s'", impl); +#endif + } + os::free((void*)impl); + return features; +}
--- a/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -47,13 +47,14 @@ cbcond_instructions = 13, sparc64_family = 14, M_family = 15, - T_family = 16, - T1_model = 17, - sparc5_instructions = 18, - aes_instructions = 19, - sha1_instruction = 20, - sha256_instruction = 21, - sha512_instruction = 22 + S_family = 16, + T_family = 17, + T1_model = 18, + sparc5_instructions = 19, + aes_instructions = 20, + sha1_instruction = 21, + sha256_instruction = 22, + sha512_instruction = 23 }; enum Feature_Flag_Set { @@ -76,6 +77,7 @@ cbcond_instructions_m = 1 << cbcond_instructions, sparc64_family_m = 1 << sparc64_family, M_family_m = 1 << M_family, + S_family_m = 1 << S_family, T_family_m = 1 << T_family, T1_model_m = 1 << T1_model, sparc5_instructions_m = 1 << sparc5_instructions, @@ -105,6 +107,7 @@ // Returns true if the platform is in the niagara line (T series) static bool is_M_family(int features) { return (features & M_family_m) != 0; } + static bool is_S_family(int features) { return (features & S_family_m) != 0; } static bool is_T_family(int features) { return (features & T_family_m) != 0; } static bool is_niagara() { return is_T_family(_features); } #ifdef ASSERT @@ -119,7 +122,7 @@ static bool is_T1_model(int features) { return is_T_family(features) && ((features & T1_model_m) != 0); } static int maximum_niagara1_processor_count() { return 32; } - + static int parse_features(const char* implementation); public: // Initialization static void initialize(); @@ -152,6 +155,7 @@ static bool is_niagara_plus() { return is_T_family(_features) && !is_T1_model(_features); } static bool is_M_series() { return is_M_family(_features); } + static bool is_S_series() { return is_S_family(_features); } static bool is_T4() { return is_T_family(_features) && has_cbcond(); } static bool is_T7() { return is_T_family(_features) && has_sparc5_instr(); }
--- a/src/cpu/x86/vm/relocInfo_x86.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -40,7 +40,7 @@ which == Assembler::imm_operand, "format unpacks ok"); if (which == Assembler::imm_operand) { if (verify_only) { - assert(*pd_address_in_code() == x, "instructions must match"); + guarantee(*pd_address_in_code() == x, "instructions must match"); } else { *pd_address_in_code() = x; } @@ -49,13 +49,13 @@ // both compressed oops and compressed classes look the same if (Universe::heap()->is_in_reserved((oop)x)) { if (verify_only) { - assert(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match"); + guarantee(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match"); } else { *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); } } else { if (verify_only) { - assert(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match"); + guarantee(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match"); } else { *(int32_t*) disp = Klass::encode_klass((Klass*)x); } @@ -66,14 +66,14 @@ address disp = Assembler::locate_operand(ip, which); address next_ip = Assembler::locate_next_instruction(ip); if (verify_only) { - assert(*(int32_t*) disp == (x - next_ip), "instructions must match"); + guarantee(*(int32_t*) disp == (x - next_ip), "instructions must match"); } else { *(int32_t*) disp = x - next_ip; } } #else if (verify_only) { - assert(*pd_address_in_code() == (x + o), "instructions must match"); + guarantee(*pd_address_in_code() == (x + o), "instructions must match"); } else { *pd_address_in_code() = x + o; }
--- a/src/cpu/x86/vm/vm_version_x86.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -406,6 +406,8 @@ _stepping = 0; _cpuFeatures = 0; _logical_processors_per_package = 1; + // i486 internal cache is both I&D and has a 16-byte line size + _L1_data_cache_line_size = 16; if (!Use486InstrsOnly) { // Get raw processor info @@ -424,6 +426,7 @@ // Logical processors are only available on P4s and above, // and only if hyperthreading is available. _logical_processors_per_package = logical_processor_count(); + _L1_data_cache_line_size = L1_line_size(); } } @@ -704,16 +707,16 @@ UseMultiplyToLenIntrinsic = true; } if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { - UseSquareToLenIntrinsic = false; + UseSquareToLenIntrinsic = true; } if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { - UseMulAddIntrinsic = false; + UseMulAddIntrinsic = true; } if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { - UseMontgomeryMultiplyIntrinsic = false; + UseMontgomeryMultiplyIntrinsic = true; } if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { - UseMontgomerySquareIntrinsic = false; + UseMontgomerySquareIntrinsic = true; } #else if (UseMultiplyToLenIntrinsic) { @@ -1039,6 +1042,7 @@ if (PrintMiscellaneous && Verbose) { tty->print_cr("Logical CPUs per core: %u", logical_processors_per_package()); + tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); tty->print("UseSSE=%d", (int) UseSSE); if (UseAVX > 0) { tty->print(" UseAVX=%d", (int) UseAVX);
--- a/src/cpu/x86/vm/vm_version_x86.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -595,7 +595,7 @@ return (result == 0 ? 1 : result); } - static intx prefetch_data_size() { + static intx L1_line_size() { intx result = 0; if (is_intel()) { result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); @@ -607,6 +607,10 @@ return result; } + static intx prefetch_data_size() { + return L1_line_size(); + } + // // Feature identification //
--- a/src/os/linux/vm/os_linux.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/os/linux/vm/os_linux.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -2919,7 +2919,7 @@ // in the library. const size_t BitsPerCLong = sizeof(long) * CHAR_BIT; - size_t cpu_num = os::active_processor_count(); + size_t cpu_num = processor_count(); size_t cpu_map_size = NCPUS / BitsPerCLong; size_t cpu_map_valid_size = MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
--- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -262,6 +262,7 @@ // We need to keep these here as long as we have to build on Solaris // versions before 10. + #ifndef SI_ARCHITECTURE_32 #define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ #endif @@ -270,231 +271,233 @@ #define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ #endif -static void do_sysinfo(int si, const char* string, int* features, int mask) { - char tmp; - size_t bufsize = sysinfo(si, &tmp, 1); +#ifndef SI_CPUBRAND +#define SI_CPUBRAND 523 /* return cpu brand string */ +#endif - // All SI defines used below must be supported. - guarantee(bufsize != -1, "must be supported"); +class Sysinfo { + char* _string; +public: + Sysinfo(int si) : _string(NULL) { + char tmp; + size_t bufsize = sysinfo(si, &tmp, 1); - char* buf = (char*) malloc(bufsize); - - if (buf == NULL) - return; + if (bufsize != -1) { + char* buf = (char*) os::malloc(bufsize, mtInternal); + if (buf != NULL) { + if (sysinfo(si, buf, bufsize) == bufsize) { + _string = buf; + } else { + os::free(buf); + } + } + } + } - if (sysinfo(si, buf, bufsize) == bufsize) { - // Compare the string. - if (strcmp(buf, string) == 0) { - *features |= mask; + ~Sysinfo() { + if (_string != NULL) { + os::free(_string); } } - free(buf); -} + const char* value() const { + return _string; + } + + bool valid() const { + return _string != NULL; + } + + bool match(const char* s) const { + return valid() ? strcmp(_string, s) == 0 : false; + } + + bool match_substring(const char* s) const { + return valid() ? strstr(_string, s) != NULL : false; + } +}; + +class Sysconf { + int _value; +public: + Sysconf(int sc) : _value(-1) { + _value = sysconf(sc); + } + bool valid() const { + return _value != -1; + } + int value() const { + return _value; + } +}; + + +#ifndef _SC_DCACHE_LINESZ +#define _SC_DCACHE_LINESZ 508 /* Data cache line size */ +#endif + +#ifndef _SC_L2CACHE_LINESZ +#define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */ +#endif + int VM_Version::platform_features(int features) { - // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are - // supported on Solaris 10 and later. - if (os::Solaris::supports_getisax()) { + assert(os::Solaris::supports_getisax(), "getisax() must be available"); - // Check 32-bit architecture. - do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + // Check 32-bit architecture. + if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) { + features |= v8_instructions_m; + } - // Check 64-bit architecture. - do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + // Check 64-bit architecture. + if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) { + features |= generic_v9_m; + } - // Extract valid instruction set extensions. - uint_t avs[2]; - uint_t avn = os::Solaris::getisax(avs, 2); - assert(avn <= 2, "should return two or less av's"); - uint_t av = avs[0]; + // Extract valid instruction set extensions. + uint_t avs[2]; + uint_t avn = os::Solaris::getisax(avs, 2); + assert(avn <= 2, "should return two or less av's"); + uint_t av = avs[0]; #ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print("getisax(2) returned: " PTR32_FORMAT, av); - if (avn > 1) { - tty->print(", " PTR32_FORMAT, avs[1]); - } - tty->cr(); + if (PrintMiscellaneous && Verbose) { + tty->print("getisax(2) returned: " PTR32_FORMAT, av); + if (avn > 1) { + tty->print(", " PTR32_FORMAT, avs[1]); } + tty->cr(); + } #endif - if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; - if (av & AV_SPARC_DIV32) features |= hardware_div32_m; - if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; - if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; - if (av & AV_SPARC_POPC) features |= hardware_popc_m; - if (av & AV_SPARC_VIS) features |= vis1_instructions_m; - if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; - if (avn > 1) { - uint_t av2 = avs[1]; + if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; + if (av & AV_SPARC_DIV32) features |= hardware_div32_m; + if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; + if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m; + if (av & AV_SPARC_POPC) features |= hardware_popc_m; + if (av & AV_SPARC_VIS) features |= vis1_instructions_m; + if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + if (avn > 1) { + uint_t av2 = avs[1]; #ifndef AV2_SPARC_SPARC5 #define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */ #endif - if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; - } + if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; + } - // Next values are not defined before Solaris 10 - // but Solaris 8 is used for jdk6 update builds. + // We only build on Solaris 10 and up, but some of the values below + // are not defined on all versions of Solaris 10, so we define them, + // if necessary. #ifndef AV_SPARC_ASI_BLK_INIT #define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */ #endif - if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; + if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; #ifndef AV_SPARC_FMAF #define AV_SPARC_FMAF 0x0100 /* Fused Multiply-Add */ #endif - if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; + if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; #ifndef AV_SPARC_FMAU -#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ +#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */ #endif - if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; + if (av & AV_SPARC_FMAU) features |= fmau_instructions_m; #ifndef AV_SPARC_VIS3 -#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ +#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */ #endif - if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; + if (av & AV_SPARC_VIS3) features |= vis3_instructions_m; #ifndef AV_SPARC_CBCOND #define AV_SPARC_CBCOND 0x10000000 /* compare and branch instrs supported */ #endif - if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m; + if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m; #ifndef AV_SPARC_AES #define AV_SPARC_AES 0x00020000 /* aes instrs supported */ #endif - if (av & AV_SPARC_AES) features |= aes_instructions_m; + if (av & AV_SPARC_AES) features |= aes_instructions_m; #ifndef AV_SPARC_SHA1 #define AV_SPARC_SHA1 0x00400000 /* sha1 instruction supported */ #endif - if (av & AV_SPARC_SHA1) features |= sha1_instruction_m; + if (av & AV_SPARC_SHA1) features |= sha1_instruction_m; #ifndef AV_SPARC_SHA256 #define AV_SPARC_SHA256 0x00800000 /* sha256 instruction supported */ #endif - if (av & AV_SPARC_SHA256) features |= sha256_instruction_m; + if (av & AV_SPARC_SHA256) features |= sha256_instruction_m; #ifndef AV_SPARC_SHA512 #define AV_SPARC_SHA512 0x01000000 /* sha512 instruction supported */ #endif - if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; - - } else { - // getisax(2) failed, use the old legacy code. -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) - tty->print_cr("getisax(2) is not supported."); -#endif - - char tmp; - size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1); - char* buf = (char*) malloc(bufsize); - - if (buf != NULL) { - if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) { - // Figure out what kind of sparc we have - char *sparc_string = strstr(buf, "sparc"); - if (sparc_string != NULL) { features |= v8_instructions_m; - if (sparc_string[5] == 'v') { - if (sparc_string[6] == '8') { - if (sparc_string[7] == '-') { features |= hardware_mul32_m; - features |= hardware_div32_m; - } else if (sparc_string[7] == 'p') features |= generic_v9_m; - else features |= generic_v8_m; - } else if (sparc_string[6] == '9') features |= generic_v9_m; - } - } - - // Check for visualization instructions - char *vis = strstr(buf, "vis"); - if (vis != NULL) { features |= vis1_instructions_m; - if (vis[3] == '2') features |= vis2_instructions_m; - } - } - free(buf); - } - } + if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; // Determine the machine type. - do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); - - { - // Using kstat to determine the machine type. - kstat_ctl_t* kc = kstat_open(); - kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); - const char* implementation = "UNKNOWN"; - if (ksp != NULL) { - if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { - kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; - for (int i = 0; i < ksp->ks_ndata; i++) { - if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { -#ifndef KSTAT_DATA_STRING -#define KSTAT_DATA_STRING 9 -#endif - if (knm[i].data_type == KSTAT_DATA_CHAR) { - // VM is running on Solaris 8 which does not have value.str. - implementation = &(knm[i].value.c[0]); - } else if (knm[i].data_type == KSTAT_DATA_STRING) { - // VM is running on Solaris 10. -#ifndef KSTAT_NAMED_STR_PTR - // Solaris 8 was used to build VM, define the structure it misses. - struct str_t { - union { - char *ptr; /* NULL-term string */ - char __pad[8]; /* 64-bit padding */ - } addr; - uint32_t len; /* # bytes for strlen + '\0' */ - }; -#define KSTAT_NAMED_STR_PTR(knptr) (( (str_t*)&((knptr)->value) )->addr.ptr) -#endif - implementation = KSTAT_NAMED_STR_PTR(&knm[i]); - } -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print_cr("cpu_info.implementation: %s", implementation); - } -#endif - // Convert to UPPER case before compare. - char* impl = strdup(implementation); - - for (int i = 0; impl[i] != 0; i++) - impl[i] = (char)toupper((uint)impl[i]); - if (strstr(impl, "SPARC64") != NULL) { - features |= sparc64_family_m; - } else if (strstr(impl, "SPARC-M") != NULL) { - // M-series SPARC is based on T-series. - features |= (M_family_m | T_family_m); - } else if (strstr(impl, "SPARC-T") != NULL) { - features |= T_family_m; - if (strstr(impl, "SPARC-T1") != NULL) { - features |= T1_model_m; - } - } else { - if (strstr(impl, "SPARC") == NULL) { -#ifndef PRODUCT - // kstat on Solaris 8 virtual machines (branded zones) - // returns "(unsupported)" implementation. - warning("kstat cpu_info implementation = '%s', should contain SPARC", impl); -#endif - implementation = "SPARC"; - } - } - free((void*)impl); - break; - } - } // for( - } - } - assert(strcmp(implementation, "UNKNOWN") != 0, - "unknown cpu info (changed kstat interface?)"); - kstat_close(kc); + if (Sysinfo(SI_MACHINE).match("sun4v")) { + features |= sun4v_m; } - // Figure out cache line sizes using PICL - PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0); - _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes + // is available to us as well + Sysinfo cpu_info(SI_CPUBRAND); + bool use_solaris_12_api = cpu_info.valid(); + const char* impl; + int impl_m = 0; + if (use_solaris_12_api) { + impl = cpu_info.value(); +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) { + tty->print_cr("Parsing CPU implementation from %s", impl); + } +#endif + impl_m = parse_features(impl); + } else { + // Otherwise use kstat to determine the machine type. + kstat_ctl_t* kc = kstat_open(); + if (kc != NULL) { + kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); + if (ksp != NULL) { + if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { + kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; + for (int i = 0; i < ksp->ks_ndata; i++) { + if (strcmp((const char*)&(knm[i].name), "implementation") == 0) { + impl = KSTAT_NAMED_STR_PTR(&knm[i]); +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) { + tty->print_cr("Parsing CPU implementation from %s", impl); + } +#endif + impl_m = parse_features(impl); + break; + } + } + } + } + kstat_close(kc); + } + } + assert(impl_m != 0, err_msg("Unknown CPU implementation %s", impl)); + features |= impl_m; + bool is_sun4v = (features & sun4v_m) != 0; + if (use_solaris_12_api && is_sun4v) { + // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes + Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); + if (l1_dcache_line_size.valid()) { + _L1_data_cache_line_size = l1_dcache_line_size.value(); + } + + Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); + if (l2_dcache_line_size.valid()) { + _L2_data_cache_line_size = l2_dcache_line_size.value(); + } + } else { + // Otherwise figure out the cache line sizes using PICL + bool is_fujitsu = (features & sparc64_family_m) != 0; + PICL picl(is_fujitsu, is_sun4v); + _L1_data_cache_line_size = picl.L1_data_cache_line_size(); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + } return features; }
--- a/src/share/vm/adlc/formssel.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/adlc/formssel.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -648,6 +648,7 @@ if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true; + if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true; if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true; if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true;
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1485,6 +1485,21 @@ // Check to see whether we are inlining. If so, Return // instructions become Gotos to the continuation point. if (continuation() != NULL) { + + int invoke_bci = state()->caller_state()->bci(); + + if (x != NULL) { + ciMethod* caller = state()->scope()->caller()->method(); + Bytecodes::Code invoke_raw_bc = caller->raw_code_at_bci(invoke_bci); + if (invoke_raw_bc == Bytecodes::_invokehandle || invoke_raw_bc == Bytecodes::_invokedynamic) { + ciType* declared_ret_type = caller->get_declared_signature_at_bci(invoke_bci)->return_type(); + if (declared_ret_type->is_klass() && x->exact_type() == NULL && + x->declared_type() != declared_ret_type && declared_ret_type != compilation()->env()->Object_klass()) { + x = append(new TypeCast(declared_ret_type->as_klass(), x, copy_state_before())); + } + } + } + assert(!method()->is_synchronized() || InlineSynchronizedMethods, "can not inline synchronized methods yet"); if (compilation()->env()->dtrace_method_probes()) { @@ -1508,7 +1523,6 @@ // State at end of inlined method is the state of the caller // without the method parameters on stack, including the // return value, if any, of the inlined method on operand stack. - int invoke_bci = state()->caller_state()->bci(); set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { state()->push(x->type(), x);
--- a/src/share/vm/c1/c1_Instruction.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/c1/c1_Instruction.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -360,7 +360,8 @@ } ciType* Invoke::declared_type() const { - ciType *t = _target->signature()->return_type(); + ciSignature* declared_signature = state()->scope()->method()->get_declared_signature_at_bci(state()->bci()); + ciType *t = declared_signature->return_type(); assert(t->basic_type() != T_VOID, "need return value of void method?"); return t; }
--- a/src/share/vm/c1/c1_LIR.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/c1/c1_LIR.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1520,6 +1520,17 @@ append(c); } +void LIR_List::null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null) { + if (deoptimize_on_null) { + // Emit an explicit null check and deoptimize if opr is null + CodeStub* deopt = new DeoptimizeStub(info); + cmp(lir_cond_equal, opr, LIR_OprFact::oopConst(NULL)); + branch(lir_cond_equal, T_OBJECT, deopt); + } else { + // Emit an implicit null check + append(new LIR_Op1(lir_null_check, opr, info)); + } +} void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2, LIR_Opr result) {
--- a/src/share/vm/c1/c1_LIR.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/c1/c1_LIR.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -2160,7 +2160,7 @@ void pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64, src, dst, T_LONG, lir_patch_none, NULL)); } void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); } - void null_check(LIR_Opr opr, CodeEmitInfo* info) { append(new LIR_Op1(lir_null_check, opr, info)); } + void null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null = false); void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info)); }
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1700,8 +1700,10 @@ if (x->needs_null_check() && (needs_patching || MacroAssembler::needs_explicit_null_check(x->offset()))) { - // emit an explicit null check because the offset is too large - __ null_check(object.result(), new CodeEmitInfo(info)); + // Emit an explicit null check because the offset is too large. + // If the class is not loaded and the object is NULL, we need to deoptimize to throw a + // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code. + __ null_check(object.result(), new CodeEmitInfo(info), /* deoptimize */ needs_patching); } LIR_Address* address; @@ -1785,8 +1787,10 @@ obj = new_register(T_OBJECT); __ move(LIR_OprFact::oopConst(NULL), obj); } - // emit an explicit null check because the offset is too large - __ null_check(obj, new CodeEmitInfo(info)); + // Emit an explicit null check because the offset is too large. + // If the class is not loaded and the object is NULL, we need to deoptimize to throw a + // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code. + __ null_check(obj, new CodeEmitInfo(info), /* deoptimize */ needs_patching); } LIR_Opr reg = rlock_result(x, field_type); @@ -3191,14 +3195,14 @@ Bytecodes::Code bc = x->method()->java_code_at_bci(bci); int start = 0; int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments(); - if (x->inlined() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) { + if (x->callee()->is_loaded() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) { // first argument is not profiled at call (method handle invoke) assert(x->method()->raw_code_at_bci(bci) == Bytecodes::_invokehandle, "invokehandle expected"); start = 1; } ciSignature* callee_signature = x->callee()->signature(); // method handle call to virtual method - bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); + bool has_receiver = x->callee()->is_loaded() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); ciSignatureStream callee_signature_stream(callee_signature, has_receiver ? x->callee()->holder() : NULL); bool ignored_will_link;
--- a/src/share/vm/ci/ciField.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/ci/ciField.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -211,7 +211,7 @@ // Check to see if the field is constant. bool is_final = this->is_final(); bool is_stable = FoldStableValues && this->is_stable(); - if (_holder->is_initialized() && (is_final || is_stable)) { + if (_holder->is_initialized() && ((is_final && !has_initialized_final_update()) || is_stable)) { if (!this->is_static()) { // A field can be constant if it's a final static field or if // it's a final non-static field of a trusted class (classes in
--- a/src/share/vm/ci/ciField.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/ci/ciField.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -124,22 +124,8 @@ return _holder->is_shared() && !is_static(); } - // Is this field a constant? - // - // Clarification: A field is considered constant if: - // 1. The field is both static and final - // 2. The canonical holder of the field has undergone - // static initialization. - // 3. If the field is an object or array, then the oop - // in question is allocated in perm space. - // 4. The field is not one of the special static/final - // non-constant fields. These are java.lang.System.in - // and java.lang.System.out. Abomination. - // - // A field is also considered constant if it is marked @Stable - // and is non-null (or non-zero, if a primitive). - // For non-static fields, the null/zero check must be - // arranged by the user, as constant_value().is_null_or_zero(). + // Is this field a constant? See ciField::initialize_from() for details + // about how a field is determined to be constant. bool is_constant() { return _is_constant; } // Get the constant value of this field. @@ -176,6 +162,9 @@ bool is_stable () { return flags().is_stable(); } bool is_volatile () { return flags().is_volatile(); } bool is_transient () { return flags().is_transient(); } + // The field is modified outside of instance initializer methods + // (or class/initializer methods if the field is static). + bool has_initialized_final_update() { return flags().has_initialized_final_update(); } bool is_call_site_target() { ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
--- a/src/share/vm/ci/ciFlags.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/ci/ciFlags.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -46,20 +46,25 @@ public: // Java access flags - bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; } - bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; } - bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; } - bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; } - bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; } - bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; } - bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; } - bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; } - bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; } - bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } - bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; } - bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; } - bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; } - bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; } + bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; } + bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; } + bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; } + bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; } + bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; } + bool is_synchronized () const { return (_flags & JVM_ACC_SYNCHRONIZED ) != 0; } + bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; } + bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; } + bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; } + bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } + bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; } + bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; } + bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; } + bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE ) != 0; } + // In case the current object represents a field, return true if + // the field is modified outside of instance initializer methods + // (or class/initializer methods if the field is static) and false + // otherwise. + bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; }; // Conversion jint as_int() { return _flags; }
--- a/src/share/vm/ci/ciMethod.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/ci/ciMethod.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -243,6 +243,21 @@ ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); + + ciSignature* get_declared_signature_at_bci(int bci) { + bool ignored_will_link; + ciSignature* declared_signature; + get_method_at_bci(bci, ignored_will_link, &declared_signature); + assert(declared_signature != NULL, "cannot be null"); + return declared_signature; + } + + ciMethod* get_method_at_bci(int bci) { + bool ignored_will_link; + ciSignature* ignored_declared_signature; + return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature); + } + // Given a certain calling environment, find the monomorphic target // for the call. Return NULL if the call is not monomorphic in // its calling environment.
--- a/src/share/vm/classfile/classFileError.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classFileError.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -56,6 +56,13 @@ msg, index, name, _class_name->as_C_string()); } +void ClassFileParser::classfile_parse_error(const char* msg, const char* name, const char* signature, TRAPS) { + assert(_class_name != NULL, "invariant"); + ResourceMark rm(THREAD); + Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), + msg, name, signature, _class_name->as_C_string()); +} + PRAGMA_DIAG_POP void StackMapStream::stackmap_format_error(const char* msg, TRAPS) {
--- a/src/share/vm/classfile/classFileParser.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classFileParser.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -821,11 +821,12 @@ THREAD, NameSigHash*, HASH_ROW_SIZE); initialize_hashtable(interface_names); bool dup = false; + Symbol* name = NULL; { debug_only(No_Safepoint_Verifier nsv;) for (index = 0; index < length; index++) { Klass* k = _local_interfaces->at(index); - Symbol* name = InstanceKlass::cast(k)->name(); + name = InstanceKlass::cast(k)->name(); // If no duplicates, add (name, NULL) in hashtable interface_names. if (!put_after_lookup(name, NULL, interface_names)) { dup = true; @@ -834,7 +835,8 @@ } } if (dup) { - classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + classfile_parse_error("Duplicate interface name \"%s\" in class file %s", + name->as_C_string(), CHECK_NULL); } } return _local_interfaces; @@ -1279,11 +1281,13 @@ THREAD, NameSigHash*, HASH_ROW_SIZE); initialize_hashtable(names_and_sigs); bool dup = false; + Symbol* name = NULL; + Symbol* sig = NULL; { debug_only(No_Safepoint_Verifier nsv;) for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) { - Symbol* name = fs.name(); - Symbol* sig = fs.signature(); + name = fs.name(); + sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(name, sig, names_and_sigs)) { dup = true; @@ -1292,8 +1296,8 @@ } } if (dup) { - classfile_parse_error("Duplicate field name&signature in class file %s", - CHECK_NULL); + classfile_parse_error("Duplicate field name \"%s\" with signature \"%s\" in class file %s", + name->as_C_string(), sig->as_klass_external_name(), CHECK_NULL); } } @@ -2580,20 +2584,24 @@ THREAD, NameSigHash*, HASH_ROW_SIZE); initialize_hashtable(names_and_sigs); bool dup = false; + Symbol* name = NULL; + Symbol* sig = NULL; { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { Method* m = _methods->at(i); + name = m->name(); + sig = m->signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. - if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { + if (!put_after_lookup(name, sig, names_and_sigs)) { dup = true; break; } } } if (dup) { - classfile_parse_error("Duplicate method name&signature in class file %s", - CHECK_NULL); + classfile_parse_error("Duplicate method name \"%s\" with signature \"%s\" in class file %s", + name->as_C_string(), sig->as_klass_external_name(), CHECK_NULL); } } }
--- a/src/share/vm/classfile/classFileParser.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classFileParser.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -314,6 +314,7 @@ void classfile_parse_error(const char* msg, int index, TRAPS); void classfile_parse_error(const char* msg, const char *name, TRAPS); void classfile_parse_error(const char* msg, int index, const char *name, TRAPS); + void classfile_parse_error(const char* msg, const char* name, const char* signature, TRAPS); inline void guarantee_property(bool b, const char* msg, TRAPS) { if (!b) { classfile_parse_error(msg, CHECK); } }
--- a/src/share/vm/classfile/classLoader.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classLoader.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1627,7 +1627,6 @@ if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); - m->clear_code(); } CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_full_optimization, methodHandle(), 0, "CTW", THREAD); @@ -1646,7 +1645,6 @@ if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); - m->clear_code(); } } }
--- a/src/share/vm/classfile/classLoaderData.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classLoaderData.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -78,7 +78,7 @@ // The null-class-loader should always be kept alive. _keep_alive(is_anonymous || h_class_loader.is_null()), _metaspace(NULL), _unloading(false), _klasses(NULL), - _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), + _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { // empty @@ -96,6 +96,45 @@ _list_head = oopFactory::new_objectArray(2, CHECK); } +ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { + Chunk* c = _head; + while (c != NULL) { + Chunk* next = c->_next; + delete c; + c = next; + } +} + +oop* ClassLoaderData::ChunkedHandleList::add(oop o) { + if (_head == NULL || _head->_size == Chunk::CAPACITY) { + Chunk* next = new Chunk(_head); + OrderAccess::release_store_ptr(&_head, next); + } + oop* handle = &_head->_data[_head->_size]; + *handle = o; + OrderAccess::release_store(&_head->_size, _head->_size + 1); + return handle; +} + +inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { + for (juint i = 0; i < size; i++) { + if (c->_data[i] != NULL) { + f->do_oop(&c->_data[i]); + } + } +} + +void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { + Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head); + if (head != NULL) { + // Must be careful when reading size of head + oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); + for (Chunk* c = head->_next; c != NULL; c = c->_next) { + oops_do_chunk(f, c, c->_size); + } + } +} + bool ClassLoaderData::claim() { if (_claimed == 1) { return false; @@ -111,7 +150,7 @@ f->do_oop(&_class_loader); _dependencies.oops_do(f); - _handles->oops_do(f); + _handles.oops_do(f); if (klass_closure != NULL) { classes_do(klass_closure); } @@ -342,11 +381,6 @@ _metaspace = NULL; // release the metaspace delete m; - // release the handles - if (_handles != NULL) { - JNIHandleBlock::release_block(_handles); - _handles = NULL; - } } // Clear all the JNI handles for methods @@ -406,15 +440,9 @@ return _metaspace; } -JNIHandleBlock* ClassLoaderData::handles() const { return _handles; } -void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; } - jobject ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); - if (handles() == NULL) { - set_handles(JNIHandleBlock::allocate_block()); - } - return handles()->allocate_handle(h()); + return (jobject) _handles.add(h()); } // Add this metadata pointer to be freed when it's safe. This is only during @@ -479,7 +507,6 @@ p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name()); if (claimed()) out->print(" claimed "); if (is_unloading()) out->print(" unloading "); - out->print(" handles " INTPTR_FORMAT, p2i(handles())); out->cr(); if (metaspace_or_null() != NULL) { out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
--- a/src/share/vm/classfile/classLoaderData.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/classLoaderData.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -51,7 +51,6 @@ class ClassLoaderData; class JNIMethodBlock; -class JNIHandleBlock; class Metadebug; // GC root for walking class loader data created @@ -145,6 +144,31 @@ void oops_do(OopClosure* f); }; + class ChunkedHandleList VALUE_OBJ_CLASS_SPEC { + struct Chunk : public CHeapObj<mtClass> { + static const size_t CAPACITY = 32; + + oop _data[CAPACITY]; + volatile juint _size; + Chunk* _next; + + Chunk(Chunk* c) : _next(c), _size(0) { } + }; + + Chunk* _head; + + void oops_do_chunk(OopClosure* f, Chunk* c, const juint size); + + public: + ChunkedHandleList() : _head(NULL) {} + ~ChunkedHandleList(); + + // Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock(). + // However, multiple threads can execute oops_do concurrently with add. + oop* add(oop o); + void oops_do(OopClosure* f); + }; + friend class ClassLoaderDataGraph; friend class ClassLoaderDataGraphKlassIteratorAtomic; friend class ClassLoaderDataGraphMetaspaceIterator; @@ -169,7 +193,8 @@ // Has to be an int because we cas it. Klass* _klasses; // The classes defined by the class loader. - JNIHandleBlock* _handles; // Handles to constant pool arrays + ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which + // have the same life cycle of the corresponding ClassLoader. // These method IDs are created for the class loader and set to NULL when the // class loader is unloaded. They are rarely freed, only for redefine classes @@ -196,9 +221,6 @@ void set_metaspace(Metaspace* m) { _metaspace = m; } - JNIHandleBlock* handles() const; - void set_handles(JNIHandleBlock* handles); - Mutex* metaspace_lock() const { return _metaspace_lock; } // GC interface.
--- a/src/share/vm/classfile/javaClasses.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/javaClasses.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -2852,6 +2852,15 @@ mname->address_field_put(_vmindex_offset, (address) index); } +bool java_lang_invoke_MemberName::equals(oop mn1, oop mn2) { + if (mn1 == mn2) { + return true; + } + return (vmtarget(mn1) == vmtarget(mn2) && flags(mn1) == flags(mn2) && + vmindex(mn1) == vmindex(mn2) && + clazz(mn1) == clazz(mn2)); +} + oop java_lang_invoke_LambdaForm::vmentry(oop lform) { assert(is_instance(lform), "wrong type"); return lform->obj_field(_vmentry_offset);
--- a/src/share/vm/classfile/javaClasses.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/javaClasses.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -1132,6 +1132,8 @@ static int flags_offset_in_bytes() { return _flags_offset; } static int vmtarget_offset_in_bytes() { return _vmtarget_offset; } static int vmindex_offset_in_bytes() { return _vmindex_offset; } + + static bool equals(oop mt1, oop mt2); };
--- a/src/share/vm/classfile/systemDictionary.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1084,15 +1084,18 @@ THREAD); const char* pkg = "java/"; + size_t pkglen = strlen(pkg); if (!HAS_PENDING_EXCEPTION && !class_loader.is_null() && parsed_name != NULL && - !strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) { + 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 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
--- a/src/share/vm/classfile/verifier.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/classfile/verifier.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -1972,7 +1972,7 @@ InstanceKlass* target_instance = InstanceKlass::cast(target_class); fieldDescriptor fd; if (is_method) { - Method* m = target_instance->uncached_lookup_method(field_name, field_sig, Klass::normal); + Method* m = target_instance->uncached_lookup_method(field_name, field_sig, Klass::find_overpass); if (m != NULL && m->is_protected()) { if (!this_class->is_same_class_package(m->method_holder())) { return true; @@ -2542,7 +2542,7 @@ Klass* ref_klass = load_class(ref_class_type.name(), CHECK); Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method( vmSymbols::object_initializer_name(), - cp->signature_ref_at(bcs->get_index_u2()), Klass::normal); + cp->signature_ref_at(bcs->get_index_u2()), Klass::find_overpass); // Do nothing if method is not found. Let resolution detect the error. if (m != NULL) { instanceKlassHandle mh(THREAD, m->method_holder());
--- a/src/share/vm/code/nmethod.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/code/nmethod.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -258,7 +258,8 @@ address ExceptionCache::test_address(address addr) { - for (int i=0; i<count(); i++) { + int limit = count(); + for (int i = 0; i < limit; i++) { if (pc_at(i) == addr) { return handler_at(i); } @@ -269,9 +270,11 @@ bool ExceptionCache::add_address_and_handler(address addr, address handler) { if (test_address(addr) == handler) return true; - if (count() < cache_size) { - set_pc_at(count(),addr); - set_handler_at(count(), handler); + + int index = count(); + if (index < cache_size) { + set_pc_at(index, addr); + set_handler_at(index, handler); increment_count(); return true; } @@ -384,10 +387,11 @@ assert(new_entry != NULL,"Must be non null"); assert(new_entry->next() == NULL, "Must be null"); - if (exception_cache() != NULL) { - new_entry->set_next(exception_cache()); + ExceptionCache *ec = exception_cache(); + if (ec != NULL) { + new_entry->set_next(ec); } - set_exception_cache(new_entry); + release_set_exception_cache(new_entry); } void nmethod::clean_exception_cache(BoolObjectClosure* is_alive) { @@ -1527,7 +1531,7 @@ if (method() != NULL && (method()->code() == this || method()->from_compiled_entry() == verified_entry_point())) { HandleMark hm; - method()->clear_code(); + method()->clear_code(false /* already owns Patching_lock */); } } // leave critical region under Patching_lock @@ -2312,7 +2316,7 @@ assert(cur != NULL, "not NULL-terminated"); nmethod* next = cur->_oops_do_mark_link; cur->_oops_do_mark_link = NULL; - cur->verify_oop_relocations(); + DEBUG_ONLY(cur->verify_oop_relocations()); NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark")); cur = next; }
--- a/src/share/vm/code/nmethod.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/code/nmethod.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -39,15 +39,16 @@ Klass* _exception_type; address _pc[cache_size]; address _handler[cache_size]; - int _count; + volatile int _count; ExceptionCache* _next; address pc_at(int index) { assert(index >= 0 && index < count(),""); return _pc[index]; } void set_pc_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _pc[index] = a; } address handler_at(int index) { assert(index >= 0 && index < count(),""); return _handler[index]; } void set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; } - int count() { return _count; } - void increment_count() { _count++; } + int count() { return OrderAccess::load_acquire(&_count); } + // increment_count is only called under lock, but there may be concurrent readers. + void increment_count() { OrderAccess::release_store(&_count, _count + 1); } public: @@ -237,7 +238,7 @@ // counter is decreased (by 1) while sweeping. int _hotness_counter; - ExceptionCache *_exception_cache; + ExceptionCache * volatile _exception_cache; PcDescCache _pc_desc_cache; // These are used for compiled synchronized native methods to @@ -433,7 +434,7 @@ // flag accessing and manipulation bool is_in_use() const { return _state == in_use; } - bool is_alive() const { return _state == in_use || _state == not_entrant; } + bool is_alive() const { unsigned char s = _state; return s == in_use || s == not_entrant; } bool is_not_entrant() const { return _state == not_entrant; } bool is_zombie() const { return _state == zombie; } bool is_unloaded() const { return _state == unloaded; } @@ -555,8 +556,10 @@ void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; } // Exception cache support + // Note: _exception_cache may be read concurrently. We rely on memory_order_consume here. ExceptionCache* exception_cache() const { return _exception_cache; } void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; } + void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); } address handler_for_exception_and_pc(Handle exception, address pc); void add_handler_for_exception_and_pc(Handle exception, address pc, address handler); void clean_exception_cache(BoolObjectClosure* is_alive);
--- a/src/share/vm/code/relocInfo.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/code/relocInfo.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -128,9 +128,9 @@ if (nm == NULL && begin != NULL) { // allow nmethod to be deduced from beginning address CodeBlob* cb = CodeCache::find_blob(begin); - nm = cb->as_nmethod_or_null(); + nm = (cb != NULL) ? cb->as_nmethod_or_null() : NULL; } - assert(nm != NULL, "must be able to deduce nmethod from other arguments"); + guarantee(nm != NULL, "must be able to deduce nmethod from other arguments"); _code = nm; _current = nm->relocation_begin() - 1;
--- a/src/share/vm/compiler/compileBroker.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1851,6 +1851,10 @@ tty->print_cr("Opening compilation log %s", file_name); } CompileLog* log = new(ResourceObj::C_HEAP, mtCompiler) CompileLog(file_name, fp, thread_id); + if (log == NULL) { + fclose(fp); + return; + } thread->init_log(log); if (xtty != NULL) {
--- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it
--- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -452,9 +452,13 @@ // event lock and do the read again in case some other thread had already // succeeded and done the resize. int cur_collection = Universe::heap()->total_collections(); - if (_last_LNC_resizing_collection[i] != cur_collection) { + // Updated _last_LNC_resizing_collection[i] must not be visible before + // _lowest_non_clean and friends are visible. Therefore use acquire/release + // to guarantee this on non TSO architecures. + if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) { MutexLocker x(ParGCRareEvent_lock); - if (_last_LNC_resizing_collection[i] != cur_collection) { + // This load_acquire is here for clarity only. The MutexLocker already fences. + if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) { if (_lowest_non_clean[i] == NULL || n_chunks != _lowest_non_clean_chunk_size[i]) { @@ -474,7 +478,8 @@ _lowest_non_clean[i][j] = NULL; } } - _last_LNC_resizing_collection[i] = cur_collection; + // Make sure this gets visible only after _lowest_non_clean* was initialized + OrderAccess::release_store(&_last_LNC_resizing_collection[i], cur_collection); } } // In any case, now do the initialization.
--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -171,7 +171,7 @@ ParallelScavengeHeap* heap = PSParallelCompact::gc_heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); - RegionTaskQueueSet* qset = ParCompactionManager::region_array(); + OopTaskQueueSet* qset = ParCompactionManager::stack_array(); ParallelTaskTerminator terminator(active_gc_threads, qset); GCTaskQueue* q = GCTaskQueue::create(); for(uint i=0; i<parallel_gc_threads; i++) {
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -2368,7 +2368,7 @@ ParallelScavengeHeap* heap = gc_heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); uint active_gc_threads = heap->gc_task_manager()->active_workers(); - TaskQueueSetSuper* qset = ParCompactionManager::region_array(); + TaskQueueSetSuper* qset = ParCompactionManager::stack_array(); ParallelTaskTerminator terminator(active_gc_threads, qset); PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
--- a/src/share/vm/interpreter/linkResolver.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/interpreter/linkResolver.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -289,11 +289,11 @@ // returns first instance method // Looks up method in classes, then looks up local default methods void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) { - Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::normal); + Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::find_overpass); result = methodHandle(THREAD, result_oop); while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) { KlassHandle super_klass = KlassHandle(THREAD, result->method_holder()->super()); - result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature, Klass::normal)); + result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature, Klass::find_overpass)); } if (klass->oop_is_array()) { @@ -320,7 +320,9 @@ // First check in default method array if (!resolved_method->is_abstract() && (InstanceKlass::cast(klass())->default_methods() != NULL)) { - int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false, false); + int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), + name, signature, Klass::find_overpass, + Klass::find_static, Klass::find_private); if (index >= 0 ) { vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index); } @@ -1189,7 +1191,7 @@ assert(resolved_method->method_holder()->is_linked(), "must be linked"); // do lookup based on receiver klass using the vtable index - if (resolved_method->method_holder()->is_interface()) { // miranda method + if (resolved_method->method_holder()->is_interface()) { // default or miranda method vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method); assert(vtable_index >= 0 , "we should have valid vtable index at this point"); @@ -1198,7 +1200,7 @@ selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index)); } else { // at this point we are sure that resolved_method is virtual and not - // a miranda method; therefore, it must have a valid vtable index. + // a default or miranda method; therefore, it must have a valid vtable index. assert(!resolved_method->has_itable_index(), ""); vtable_index = resolved_method->vtable_index(); // We could get a negative vtable_index for final methods,
--- a/src/share/vm/interpreter/rewriter.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/interpreter/rewriter.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -396,10 +396,45 @@ break; } + case Bytecodes::_putstatic : + case Bytecodes::_putfield : { + if (!reverse) { + // Check if any final field of the class given as parameter is modified + // outside of initializer methods of the class. Fields that are modified + // are marked with a flag. For marked fields, the compilers do not perform + // constant folding (as the field can be changed after initialization). + // + // The check is performed after verification and only if verification has + // succeeded. Therefore, the class is guaranteed to be well-formed. + InstanceKlass* klass = method->method_holder(); + u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1); + constantPoolHandle cp(method->constants()); + Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index)); + + if (klass->name() == ref_class_name) { + Symbol* field_name = cp->name_ref_at(bc_index); + Symbol* field_sig = cp->signature_ref_at(bc_index); + + fieldDescriptor fd; + if (klass->find_field(field_name, field_sig, &fd) != NULL) { + if (fd.access_flags().is_final()) { + if (fd.access_flags().is_static()) { + if (!method->is_static_initializer()) { + fd.set_has_initialized_final_update(true); + } + } else { + if (!method->is_object_initializer()) { + fd.set_has_initialized_final_update(true); + } + } + } + } + } + } + } + // fall through case Bytecodes::_getstatic : // fall through - case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : // fall through case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokestatic : case Bytecodes::_invokeinterface:
--- a/src/share/vm/memory/cardTableModRefBS.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/memory/cardTableModRefBS.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -217,7 +217,7 @@ CardArr* _lowest_non_clean; size_t* _lowest_non_clean_chunk_size; uintptr_t* _lowest_non_clean_base_chunk_index; - int* _last_LNC_resizing_collection; + volatile int* _last_LNC_resizing_collection; // Initializes "lowest_non_clean" to point to the array for the region // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
--- a/src/share/vm/oops/arrayKlass.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/arrayKlass.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -71,10 +71,13 @@ return super()->find_field(name, sig, fd); } -Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const { +Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const { // There are no methods in an array klass but the super class (Object) has some assert(super(), "super klass must be present"); - return super()->uncached_lookup_method(name, signature, mode); + // Always ignore overpass methods in superclasses, although technically the + // super klass of an array, (j.l.Object) should not have + // any overpass methods present. + return super()->uncached_lookup_method(name, signature, Klass::skip_overpass); } ArrayKlass::ArrayKlass(Symbol* name) {
--- a/src/share/vm/oops/arrayKlass.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/arrayKlass.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -90,7 +90,7 @@ Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const; // Lookup operations - Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const; + Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const; // Casting from Klass* static ArrayKlass* cast(Klass* k) {
--- a/src/share/vm/oops/constMethod.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/constMethod.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -390,8 +390,12 @@ ResourceMark rm; assert(is_constMethod(), "must be constMethod"); st->print_cr("%s", internal_name()); - st->print(" - method: " INTPTR_FORMAT " ", p2i((address)method())); - method()->print_value_on(st); st->cr(); + Method* m = method(); + st->print(" - method: " INTPTR_FORMAT " ", p2i((address)m)); + if (m != NULL) { + m->print_value_on(st); + } + st->cr(); if (has_stackmap_table()) { st->print(" - stackmap data: "); stackmap_data()->print_value_on(st); @@ -404,7 +408,12 @@ void ConstMethod::print_value_on(outputStream* st) const { assert(is_constMethod(), "must be constMethod"); st->print(" const part of method " ); - method()->print_value_on(st); + Method* m = method(); + if (m != NULL) { + m->print_value_on(st); + } else { + st->print("NULL"); + } } #if INCLUDE_SERVICES @@ -444,7 +453,7 @@ // Verification can occur during oop construction before the method or // other fields have been initialized. - guarantee(method()->is_method(), "should be method"); + guarantee(method() != NULL && method()->is_method(), "should be method"); address m_end = (address)((intptr_t) this + size()); address compressed_table_start = code_end();
--- a/src/share/vm/oops/instanceKlass.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/instanceKlass.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -616,7 +616,11 @@ bool InstanceKlass::link_class_impl( instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { - // check for error state + // check for error state. + // This is checking for the wrong state. If the state is initialization_error, + // then this class *was* linked. The CDS code does a try_link_class and uses + // initialization_error to mark classes to not include in the archive during + // DumpSharedSpaces. This should be removed when the CDS bug is fixed. if (this_oop->is_in_error_state()) { ResourceMark rm(THREAD); THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(), @@ -801,37 +805,22 @@ } // Eagerly initialize superinterfaces that declare default methods (concrete instance: any access) -void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_oop, TRAPS) { - if (this_oop->has_default_methods()) { - for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) { - Klass* iface = this_oop->local_interfaces()->at(i); - InstanceKlass* ik = InstanceKlass::cast(iface); - if (ik->should_be_initialized()) { - if (ik->has_default_methods()) { - ik->initialize_super_interfaces(ik, THREAD); - } - // Only initialize() interfaces that "declare" concrete methods. - // has_default_methods drives searching superinterfaces since it - // means has_default_methods in its superinterface hierarchy - if (!HAS_PENDING_EXCEPTION && ik->declares_default_methods()) { - ik->initialize(THREAD); - } - if (HAS_PENDING_EXCEPTION) { - Handle e(THREAD, PENDING_EXCEPTION); - CLEAR_PENDING_EXCEPTION; - { - EXCEPTION_MARK; - // Locks object, set state, and notify all waiting threads - this_oop->set_initialization_state_and_notify( - initialization_error, THREAD); - - // ignore any exception thrown, superclass initialization error is - // thrown below - CLEAR_PENDING_EXCEPTION; - } - THROW_OOP(e()); - } - } +void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_k, TRAPS) { + assert (this_k->has_default_methods(), "caller should have checked this"); + for (int i = 0; i < this_k->local_interfaces()->length(); ++i) { + Klass* iface = this_k->local_interfaces()->at(i); + InstanceKlass* ik = InstanceKlass::cast(iface); + + // Initialization is depth first search ie. we start with top of the inheritance tree + // has_default_methods drives searching superinterfaces since it + // means has_default_methods in its superinterface hierarchy + if (ik->has_default_methods()) { + ik->initialize_super_interfaces(ik, CHECK); + } + + // Only initialize() interfaces that "declare" concrete methods. + if (ik->should_be_initialized() && ik->declares_default_methods()) { + ik->initialize(CHECK); } } } @@ -897,30 +886,36 @@ } // Step 7 - Klass* super_klass = this_oop->super(); - if (super_klass != NULL && !this_oop->is_interface() && super_klass->should_be_initialized()) { - super_klass->initialize(THREAD); - + // Next, if C is a class rather than an interface, initialize its super class and super + // interfaces. + if (!this_oop->is_interface()) { + Klass* super_klass = this_oop->super(); + if (super_klass != NULL && super_klass->should_be_initialized()) { + super_klass->initialize(THREAD); + } + // If C implements any interfaces that declares a non-abstract, non-static method, + // the initialization of C triggers initialization of its super interfaces. + // Only need to recurse if has_default_methods which includes declaring and + // inheriting default methods + if (!HAS_PENDING_EXCEPTION && this_oop->has_default_methods()) { + this_oop->initialize_super_interfaces(this_oop, THREAD); + } + + // If any exceptions, complete abruptly, throwing the same exception as above. if (HAS_PENDING_EXCEPTION) { Handle e(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; { EXCEPTION_MARK; - this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads - CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below + // Locks object, set state, and notify all waiting threads + this_oop->set_initialization_state_and_notify(initialization_error, THREAD); + CLEAR_PENDING_EXCEPTION; } DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait); THROW_OOP(e()); } } - // Recursively initialize any superinterfaces that declare default methods - // Only need to recurse if has_default_methods which includes declaring and - // inheriting default methods - if (this_oop->has_default_methods()) { - this_oop->initialize_super_interfaces(this_oop, CHECK); - } - // Step 8 { assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl"); @@ -981,10 +976,15 @@ void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) { oop init_lock = this_oop->init_lock(); - ObjectLocker ol(init_lock, THREAD, init_lock != NULL); - this_oop->set_init_state(state); - this_oop->fence_and_clear_init_lock(); - ol.notify_all(CHECK); + if (init_lock != NULL) { + ObjectLocker ol(init_lock, THREAD); + this_oop->set_init_state(state); + this_oop->fence_and_clear_init_lock(); + ol.notify_all(CHECK); + } else { + assert(init_lock != NULL, "The initialization state should never be set twice"); + this_oop->set_init_state(state); + } } // The embedded _implementor field can only record one implementor. @@ -1475,18 +1475,23 @@ // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const { - return find_method_impl(name, signature, false); + return find_method_impl(name, signature, find_overpass, find_static, find_private); } -Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const { - return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass, false); +Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const { + return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode); } // find_instance_method looks up the name/signature in the local methods array // and skips over static methods Method* InstanceKlass::find_instance_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - Method* meth = InstanceKlass::find_method_impl(methods, name, signature, false, true); + Method* meth = InstanceKlass::find_method_impl(methods, name, signature, + find_overpass, skip_static, find_private); + assert(((meth == NULL) || !meth->is_static()), "find_instance_method should have skipped statics"); return meth; } @@ -1496,22 +1501,51 @@ return InstanceKlass::find_instance_method(methods(), name, signature); } +// Find looks up the name/signature in the local methods array +// and filters on the overpass, static and private flags +// This returns the first one found +// note that the local methods array can have up to one overpass, one static +// and one instance (private or not) with the same name/signature +Method* InstanceKlass::find_local_method(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const { + return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode); +} + +// Find looks up the name/signature in the local methods array +// and filters on the overpass, static and private flags +// This returns the first one found +// note that the local methods array can have up to one overpass, one static +// and one instance (private or not) with the same name/signature +Method* InstanceKlass::find_local_method(Array<Method*>* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) { + return InstanceKlass::find_method_impl(methods, name, signature, overpass_mode, static_mode, private_mode); +} + + // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method( Array<Method*>* methods, Symbol* name, Symbol* signature) { - return InstanceKlass::find_method_impl(methods, name, signature, false, false); + return InstanceKlass::find_method_impl(methods, name, signature, find_overpass, find_static, find_private); } Method* InstanceKlass::find_method_impl( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { - int hit = find_method_index(methods, name, signature, skipping_overpass, skipping_static); + Array<Method*>* methods, Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, StaticLookupMode static_mode, + PrivateLookupMode private_mode) { + int hit = find_method_index(methods, name, signature, overpass_mode, static_mode, private_mode); return hit >= 0 ? methods->at(hit): NULL; } -bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) { - return (m->signature() == signature) && +bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private) { + return ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass()) && - (!skipping_static || !m->is_static()); + (!skipping_static || !m->is_static()) && + (!skipping_private || !m->is_private())); } // Used directly for default_methods to find the index into the @@ -1521,15 +1555,25 @@ // the search continues to find a potential non-overpass match. This capability // is important during method resolution to prefer a static method, for example, // over an overpass method. +// There is the possibility in any _method's array to have the same name/signature +// for a static method, an overpass method and a local instance method +// To correctly catch a given method, the search criteria may need +// to explicitly skip the other two. For local instance methods, it +// is often necessary to skip private methods int InstanceKlass::find_method_index( - Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) { + Array<Method*>* methods, Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, StaticLookupMode static_mode, + PrivateLookupMode private_mode) { + bool skipping_overpass = (overpass_mode == skip_overpass); + bool skipping_static = (static_mode == skip_static); + bool skipping_private = (private_mode == skip_private); int hit = binary_search(methods, name); if (hit != -1) { Method* m = methods->at(hit); // Do linear search to find matching signature. First, quick check // for common case, ignoring overpasses if requested. - if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return hit; // search downwards through overloaded methods int i; @@ -1537,18 +1581,18 @@ Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i; } // search upwards for (i = hit + 1; i < methods->length(); ++i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i; } // not found #ifdef ASSERT - int index = skipping_overpass || skipping_static ? -1 : linear_search(methods, name, signature); + int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature); assert(index == -1, err_msg("binary search should have found entry %d", index)); #endif } @@ -1574,16 +1618,16 @@ // uncached_lookup_method searches both the local class methods array and all // superclasses methods arrays, skipping any overpass methods in superclasses. -Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const { - MethodLookupMode lookup_mode = mode; +Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const { + OverpassLookupMode overpass_local_mode = overpass_mode; Klass* klass = const_cast<InstanceKlass*>(this); while (klass != NULL) { - Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, (lookup_mode == skip_overpass)); + Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, overpass_local_mode, find_static, find_private); if (method != NULL) { return method; } klass = InstanceKlass::cast(klass)->super(); - lookup_mode = skip_overpass; // Always ignore overpass methods in superclasses + overpass_local_mode = skip_overpass; // Always ignore overpass methods in superclasses } return NULL; } @@ -1613,7 +1657,7 @@ } // Look up interfaces if (m == NULL) { - m = lookup_method_in_all_interfaces(name, signature, normal); + m = lookup_method_in_all_interfaces(name, signature, find_defaults); } return m; } @@ -1623,7 +1667,7 @@ // They should only be found in the initial InterfaceMethodRef Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, - MethodLookupMode mode) const { + DefaultsLookupMode defaults_mode) const { Array<Klass*>* all_ifs = transitive_interfaces(); int num_ifs = all_ifs->length(); InstanceKlass *ik = NULL; @@ -1631,7 +1675,7 @@ ik = InstanceKlass::cast(all_ifs->at(i)); Method* m = ik->lookup_method(name, signature); if (m != NULL && m->is_public() && !m->is_static() && - ((mode != skip_defaults) || !m->is_default_method())) { + ((defaults_mode != skip_defaults) || !m->is_default_method())) { return m; } } @@ -3018,7 +3062,7 @@ return NULL; } -bool InstanceKlass::add_member_name(Handle mem_name) { +oop InstanceKlass::add_member_name(Handle mem_name, bool intern) { jweak mem_name_wref = JNIHandles::make_weak_global(mem_name); MutexLocker ml(MemberNameTable_lock); DEBUG_ONLY(No_Safepoint_Verifier nsv); @@ -3028,7 +3072,7 @@ // is called! Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mem_name()); if (method->is_obsolete()) { - return false; + return NULL; } else if (method->is_old()) { // Replace method with redefined version java_lang_invoke_MemberName::set_vmtarget(mem_name(), method_with_idnum(method->method_idnum())); @@ -3037,8 +3081,11 @@ if (_member_names == NULL) { _member_names = new (ResourceObj::C_HEAP, mtClass) MemberNameTable(idnum_allocated_count()); } - _member_names->add_member_name(mem_name_wref); - return true; + if (intern) { + return _member_names->find_or_add_member_name(mem_name_wref); + } else { + return _member_names->add_member_name(mem_name_wref); + } } // -----------------------------------------------------------------------------------------------------
--- a/src/share/vm/oops/instanceKlass.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/instanceKlass.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -527,18 +527,36 @@ Method* find_instance_method(Symbol* name, Symbol* signature); static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature); - // true if method matches signature and conforms to skipping_X conditions. - static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static); + // find a local method (returns NULL if not found) + Method* find_local_method(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const; - // find a local method index in default_methods (returns -1 if not found) - static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); + // find a local method from given methods array (returns NULL if not found) + static Method* find_local_method(Array<Method*>* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); + + // true if method matches signature and conforms to skipping_X conditions. + static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private); + + // find a local method index in methods or default_methods (returns -1 if not found) + static int find_method_index(Array<Method*>* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); + // lookup operation (returns NULL if not found) - Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const; + Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const; // lookup a method in all the interfaces that this class implements // (returns NULL if not found) - Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, MethodLookupMode mode) const; + Method* lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, DefaultsLookupMode defaults_mode) const; // lookup a method in local defaults then in all interfaces // (returns NULL if not found) @@ -1089,8 +1107,15 @@ Klass* array_klass_impl(bool or_null, TRAPS); // find a local method (returns NULL if not found) - Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const; - static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static); + Method* find_method_impl(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const; + static Method* find_method_impl(Array<Method*>* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); // Free CHeap allocated fields. void release_C_heap_structures(); @@ -1105,7 +1130,7 @@ // JSR-292 support MemberNameTable* member_names() { return _member_names; } void set_member_names(MemberNameTable* member_names) { _member_names = member_names; } - bool add_member_name(Handle member_name); + oop add_member_name(Handle member_name, bool intern); public: // JVMTI support
--- a/src/share/vm/oops/klass.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/klass.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -140,7 +140,7 @@ return NULL; } -Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const { +Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const { #ifdef ASSERT tty->print_cr("Error: uncached_lookup_method called on a klass oop." " Likely error: reflection method does not correctly"
--- a/src/share/vm/oops/klass.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/klass.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -192,7 +192,10 @@ void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw(); public: - enum MethodLookupMode { normal, skip_overpass, skip_defaults }; + enum DefaultsLookupMode { find_defaults, skip_defaults }; + enum OverpassLookupMode { find_overpass, skip_overpass }; + enum StaticLookupMode { find_static, skip_static }; + enum PrivateLookupMode { find_private, skip_private }; bool is_klass() const volatile { return true; } @@ -458,10 +461,10 @@ // lookup operation for MethodLookupCache friend class MethodLookupCache; virtual Klass* find_field(Symbol* name, Symbol* signature, fieldDescriptor* fd) const; - virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const; + virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const; public: Method* lookup_method(Symbol* name, Symbol* signature) const { - return uncached_lookup_method(name, signature, normal); + return uncached_lookup_method(name, signature, find_overpass); } // array class with specific rank
--- a/src/share/vm/oops/klassVtable.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/klassVtable.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -696,7 +696,7 @@ // this check for all access permissions. InstanceKlass *sk = InstanceKlass::cast(super); if (sk->has_miranda_methods()) { - if (sk->lookup_method_in_all_interfaces(name, signature, Klass::normal) != NULL) { + if (sk->lookup_method_in_all_interfaces(name, signature, Klass::find_defaults) != NULL) { return false; // found a matching miranda; we do not need a new entry } } @@ -729,7 +729,6 @@ if (mhk->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(method_holder) , "this class should implement the interface"); - // the search could find a miranda or a default method if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super())) { return true; } @@ -737,25 +736,57 @@ return false; } -// check if a method is a miranda method, given a class's methods table, -// its default_method table and its super -// Miranda methods are calculated twice: -// first: before vtable size calculation: including abstract and superinterface default +// Check if a method is a miranda method, given a class's methods array, +// its default_method table and its super class. +// "Miranda" means an abstract non-private method that would not be +// overridden for the local class. +// A "miranda" method should only include non-private interface +// instance methods, i.e. not private methods, not static methods, +// not default methods (concrete interface methods), not overpass methods. +// If a given class already has a local (including overpass) method, a +// default method, or any of its superclasses has the same which would have +// overridden an abstract method, then this is not a miranda method. +// +// Miranda methods are checked multiple times. +// Pass 1: during class load/class file parsing: before vtable size calculation: +// include superinterface abstract and default methods (non-private instance). // We include potential default methods to give them space in the vtable. -// During the first run, the default_methods list is empty -// This is seen by default method creation -// Second: recalculated during vtable initialization: only include abstract methods. +// During the first run, the current instanceKlass has not yet been +// created, the superclasses and superinterfaces do have instanceKlasses +// but may not have vtables, the default_methods list is empty, no overpasses. +// This is seen by default method creation. +// +// Pass 2: recalculated during vtable initialization: only include abstract methods. +// The goal of pass 2 is to walk through the superinterfaces to see if any of +// the superinterface methods (which were all abstract pre-default methods) +// need to be added to the vtable. +// With the addition of default methods, we have three new challenges: +// overpasses, static interface methods and private interface methods. +// Static and private interface methods do not get added to the vtable and +// are not seen by the method resolution process, so we skip those. +// Overpass methods are already in the vtable, so vtable lookup will +// find them and we don't need to add a miranda method to the end of +// the vtable. So we look for overpass methods and if they are found we +// return false. Note that we inherit our superclasses vtable, so +// the superclass' search also needs to use find_overpass so that if +// one is found we return false. +// False means - we don't need a miranda method added to the vtable. +// // During the second run, default_methods is set up, so concrete methods from // superinterfaces with matching names/signatures to default_methods are already // in the default_methods list and do not need to be appended to the vtable -// as mirandas -// This is seen by link resolution and selection. -// "miranda" means not static, not defined by this class. -// private methods in interfaces do not belong in the miranda list. -// the caller must make sure that the method belongs to an interface implemented by the class -// Miranda methods only include public interface instance methods -// Not private methods, not static methods, not default == concrete abstract -// Miranda methods also do not include overpass methods in interfaces +// as mirandas. Abstract methods may already have been handled via +// overpasses - either local or superclass overpasses, which may be +// in the vtable already. +// +// Pass 3: They are also checked by link resolution and selection, +// for invocation on a method (not interface method) reference that +// resolves to a method with an interface as its method_holder. +// Used as part of walking from the bottom of the vtable to find +// the vtable index for the miranda method. +// +// Part of the Miranda Rights in the US mean that if you do not have +// an attorney one will be appointed for you. bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Array<Method*>* default_methods, Klass* super) { if (m->is_static() || m->is_private() || m->is_overpass()) { @@ -763,44 +794,36 @@ } Symbol* name = m->name(); Symbol* signature = m->signature(); - Method* mo; - if ((mo = InstanceKlass::find_instance_method(class_methods, name, signature)) == NULL) { - // did not find it in the method table of the current class - if ((default_methods == NULL) || - InstanceKlass::find_method(default_methods, name, signature) == NULL) { - if (super == NULL) { - // super doesn't exist - return true; - } - - mo = InstanceKlass::cast(super)->lookup_method(name, signature); - while (mo != NULL && mo->access_flags().is_static() - && mo->method_holder() != NULL - && mo->method_holder()->super() != NULL) - { - mo = mo->method_holder()->super()->uncached_lookup_method(name, signature, Klass::normal); - } - if (mo == NULL || mo->access_flags().is_private() ) { - // super class hierarchy does not implement it or protection is different - return true; - } - } - } else { - // if the local class has a private method, the miranda will not - // override it, so a vtable slot is needed - if (mo->access_flags().is_private()) { - - // Second round, weed out any superinterface methods that turned - // into default methods, i.e. were concrete not abstract in the end - if ((default_methods == NULL) || - InstanceKlass::find_method(default_methods, name, signature) == NULL) { - return true; - } - } + // First look in local methods to see if already covered + if (InstanceKlass::find_local_method(class_methods, name, signature, + Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) + { + return false; } - return false; + // Check local default methods + if ((default_methods != NULL) && + (InstanceKlass::find_method(default_methods, name, signature) != NULL)) + { + return false; + } + + InstanceKlass* cursuper; + // Iterate on all superclasses, which should have instanceKlasses + // Note that we explicitly look for overpasses at each level. + // Overpasses may or may not exist for supers for pass 1, + // they should have been created for pass 2 and later. + + for (cursuper = InstanceKlass::cast(super); cursuper != NULL; cursuper = (InstanceKlass*)cursuper->super()) + { + if (cursuper->find_local_method(name, signature, + Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) { + return false; + } + } + + return true; } // Scans current_interface_methods for miranda methods that do not @@ -836,7 +859,7 @@ if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all? InstanceKlass *sk = InstanceKlass::cast(super); // check if it is a duplicate of a super's miranda - if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::normal) == NULL) { + if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::find_defaults) == NULL) { new_mirandas->append(im); } if (all_mirandas != NULL) {
--- a/src/share/vm/oops/method.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/method.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -98,7 +98,7 @@ // Fix and bury in Method* set_interpreter_entry(NULL); // sets i2i entry and from_int set_adapter_entry(NULL); - clear_code(); // from_c/from_i get set to c2i/i2i + clear_code(false /* don't need a lock */); // from_c/from_i get set to c2i/i2i if (access_flags.is_native()) { clear_native_function(); @@ -595,7 +595,7 @@ } bool Method::is_initializer() const { - return name() == vmSymbols::object_initializer_name() || is_static_initializer(); + return is_object_initializer() || is_static_initializer(); } bool Method::has_valid_initializer_flags() const { @@ -611,6 +611,9 @@ has_valid_initializer_flags(); } +bool Method::is_object_initializer() const { + return name() == vmSymbols::object_initializer_name(); +} objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) { int length = this_oop->checked_exceptions_length(); @@ -860,8 +863,8 @@ } // Revert to using the interpreter and clear out the nmethod -void Method::clear_code() { - +void Method::clear_code(bool acquire_lock /* = true */) { + MutexLockerEx pl(acquire_lock ? Patching_lock : NULL, Mutex::_no_safepoint_check_flag); // this may be NULL if c2i adapters have not been made yet // Only should happen at allocate time. if (_adapter == NULL) { @@ -989,6 +992,7 @@ // Install compiled code. Instantly it can execute. void Method::set_code(methodHandle mh, nmethod *code) { + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); assert( code, "use clear_code to remove code" ); assert( mh->check_code(), "" );
--- a/src/share/vm/oops/method.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/oops/method.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -444,7 +444,7 @@ address verified_code_entry(); bool check_code() const; // Not inline to avoid circular ref nmethod* volatile code() const { assert( check_code(), "" ); return (nmethod *)OrderAccess::load_ptr_acquire(&_code); } - void clear_code(); // Clear out any compiled code + void clear_code(bool acquire_lock = true); // Clear out any compiled code static void set_code(methodHandle mh, nmethod* code); void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; } address get_i2c_entry(); @@ -632,6 +632,9 @@ // valid static initializer flags. bool is_static_initializer() const; + // returns true if the method name is <init> + bool is_object_initializer() const; + // compiled code support // NOTE: code() is inherently racy as deopt can be clearing code // simultaneously. Use with caution.
--- a/src/share/vm/opto/block.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/block.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1208,6 +1208,9 @@ if (j >= 1 && n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_CreateEx) { assert(j == 1 || block->get_node(j-1)->is_Phi(), "CreateEx must be first instruction in block"); } + if (n->needs_anti_dependence_check()) { + verify_anti_dependences(block, n); + } for (uint k = 0; k < n->req(); k++) { Node *def = n->in(k); if (def && def != n) {
--- a/src/share/vm/opto/block.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/block.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -185,14 +185,13 @@ Block* lone_fall_through(); // Return lone fall-through Block or null Block* dom_lca(Block* that); // Compute LCA in dominator tree. -#ifdef ASSERT + bool dominates(Block* that) { int dom_diff = this->_dom_depth - that->_dom_depth; if (dom_diff > 0) return false; for (; dom_diff < 0; dom_diff++) that = that->_idom; return this == that; } -#endif // Report the alignment required by this block. Must be a power of 2. // The previous block will insert nops to get this alignment. @@ -473,9 +472,9 @@ MachNode* _goto; Block* insert_anti_dependences(Block* LCA, Node* load, bool verify = false); - void verify_anti_dependences(Block* LCA, Node* load) { + void verify_anti_dependences(Block* LCA, Node* load) const { assert(LCA == get_block_for_node(load), "should already be scheduled"); - insert_anti_dependences(LCA, load, true); + const_cast<PhaseCFG*>(this)->insert_anti_dependences(LCA, load, true); } bool move_to_next(Block* bx, uint b_index);
--- a/src/share/vm/opto/callGenerator.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/callGenerator.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -188,7 +188,10 @@ // the call instruction will have a seemingly deficient out-count. // (The bailout says something misleading about an "infinite loop".) if (kit.gvn().type(receiver)->higher_equal(TypePtr::NULL_PTR)) { - kit.inc_sp(method()->arg_size()); // restore arguments + assert(Bytecodes::is_invoke(kit.java_bc()), err_msg("%d: %s", kit.java_bc(), Bytecodes::name(kit.java_bc()))); + ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci()); + int arg_size = declared_method->signature()->arg_size_for_bc(kit.java_bc()); + kit.inc_sp(arg_size); // restore arguments kit.uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none, NULL, "null receiver"); @@ -1119,7 +1122,10 @@ JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); // Take the trap with arguments pushed on the stack. (Cf. null_check_receiver). - int nargs = method()->arg_size(); + // Callsite signature can be different from actual method being called (i.e _linkTo* sites). + // Use callsite signature always. + ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci()); + int nargs = declared_method->arg_size(); kit.inc_sp(nargs); assert(nargs <= kit.sp() && kit.sp() <= jvms->stk_size(), "sane sp w/ args pushed"); if (_reason == Deoptimization::Reason_class_check &&
--- a/src/share/vm/opto/callnode.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/callnode.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -743,8 +743,8 @@ } // May modify (by reflection) if an boxing object is passed // as argument or returned. - if (returns_pointer() && (proj_out(TypeFunc::Parms) != NULL)) { - Node* proj = proj_out(TypeFunc::Parms); + Node* proj = returns_pointer() ? proj_out(TypeFunc::Parms) : NULL; + if (proj != NULL) { const TypeInstPtr* inst_t = phase->type(proj)->isa_instptr(); if ((inst_t != NULL) && (!inst_t->klass_is_exact() || (inst_t->klass() == boxing_klass))) {
--- a/src/share/vm/opto/cfgnode.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/cfgnode.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -119,6 +119,9 @@ // input in slot 0. class PhiNode : public TypeNode { const TypePtr* const _adr_type; // non-null only for Type::MEMORY nodes. + // The following fields are only used for data PhiNodes to indicate + // that the PhiNode represents the value of a known instance field. + int _inst_mem_id; // Instance memory id (node index of the memory Phi) const int _inst_id; // Instance id of the memory slice. const int _inst_index; // Alias index of the instance memory slice. // Array elements references have the same alias_idx but different offset. @@ -138,11 +141,13 @@ }; PhiNode( Node *r, const Type *t, const TypePtr* at = NULL, + const int imid = -1, const int iid = TypeOopPtr::InstanceTop, const int iidx = Compile::AliasIdxTop, const int ioffs = Type::OffsetTop ) : TypeNode(t,r->req()), _adr_type(at), + _inst_mem_id(imid), _inst_id(iid), _inst_index(iidx), _inst_offset(ioffs) @@ -187,11 +192,14 @@ virtual bool pinned() const { return in(0) != 0; } virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; } + void set_inst_mem_id(int inst_mem_id) { _inst_mem_id = inst_mem_id; } + const int inst_mem_id() const { return _inst_mem_id; } const int inst_id() const { return _inst_id; } const int inst_index() const { return _inst_index; } const int inst_offset() const { return _inst_offset; } - bool is_same_inst_field(const Type* tp, int id, int index, int offset) { + bool is_same_inst_field(const Type* tp, int mem_id, int id, int index, int offset) { return type()->basic_type() == tp->basic_type() && + inst_mem_id() == mem_id && inst_id() == id && inst_index() == index && inst_offset() == offset &&
--- a/src/share/vm/opto/compile.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/compile.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1631,6 +1631,17 @@ } } +BasicType Compile::AliasType::basic_type() const { + if (element() != NULL) { + const Type* element = adr_type()->is_aryptr()->elem(); + return element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); + } if (field() != NULL) { + return field()->layout_type(); + } else { + return T_ILLEGAL; // unknown + } +} + //---------------------------------print_on------------------------------------ #ifndef PRODUCT void Compile::AliasType::print_on(outputStream* st) {
--- a/src/share/vm/opto/compile.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/compile.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -152,6 +152,8 @@ _element = e; } + BasicType basic_type() const; + void print_on(outputStream* st) PRODUCT_RETURN; };
--- a/src/share/vm/opto/connode.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/connode.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -999,8 +999,7 @@ } #ifdef _LP64 - // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or - // ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))), + // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) // but only if x and y have subranges that cannot cause 32-bit overflow, // under the assumption that x+y is in my own subrange this->type(). @@ -1024,13 +1023,6 @@ Node* z = in(1); int op = z->Opcode(); - Node* ctrl = NULL; - if (op == Op_CastII && z->as_CastII()->has_range_check()) { - // Skip CastII node but save control dependency - ctrl = z->in(0); - z = z->in(1); - op = z->Opcode(); - } if (op == Op_AddI || op == Op_SubI) { Node* x = z->in(1); Node* y = z->in(2); @@ -1090,8 +1082,8 @@ } assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow"); assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow"); - Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl); - Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl); + Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), NULL); + Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), NULL); switch (op) { case Op_AddI: return new (phase->C) AddLNode(cx, cy); case Op_SubI: return new (phase->C) SubLNode(cx, cy);
--- a/src/share/vm/opto/graphKit.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/graphKit.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1452,7 +1452,11 @@ // factory methods in "int adr_idx" Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) { + MemNode::MemOrd mo, + LoadNode::ControlDependency control_dependency, + bool require_atomic_access, + bool unaligned, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = NULL; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1465,6 +1469,12 @@ } else { ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); } + if (unaligned) { + ld->as_Load()->set_unaligned_access(); + } + if (mismatched) { + ld->as_Load()->set_mismatched_access(); + } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { // Improve graph before escape analysis and boxing elimination. @@ -1476,7 +1486,9 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, int adr_idx, MemNode::MemOrd mo, - bool require_atomic_access) { + bool require_atomic_access, + bool unaligned, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); const TypePtr* adr_type = NULL; debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1489,6 +1501,12 @@ } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } + if (unaligned) { + st->as_Store()->set_unaligned_access(); + } + if (mismatched) { + st->as_Store()->set_mismatched_access(); + } st = _gvn.transform(st); set_memory(st, adr_idx); // Back-to-back stores can only remove intermediate store with DU info @@ -1588,7 +1606,8 @@ const TypeOopPtr* val_type, BasicType bt, bool use_precise, - MemNode::MemOrd mo) { + MemNode::MemOrd mo, + bool mismatched) { // Transformation of a value which could be NULL pointer (CastPP #NULL) // could be delayed during Parse (for example, in adjust_map_after_if()). // Execute transformation here to avoid barrier generation in such case. @@ -1608,7 +1627,7 @@ NULL /* pre_val */, bt); - Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo); + Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo, mismatched); post_barrier(control(), store, obj, adr, adr_idx, val, bt, use_precise); return store; } @@ -1620,7 +1639,8 @@ const TypePtr* adr_type, Node* val, BasicType bt, - MemNode::MemOrd mo) { + MemNode::MemOrd mo, + bool mismatched) { Compile::AliasType* at = C->alias_type(adr_type); const TypeOopPtr* val_type = NULL; if (adr_type->isa_instptr()) { @@ -1639,7 +1659,7 @@ if (val_type == NULL) { val_type = TypeInstPtr::BOTTOM; } - return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo); + return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo, mismatched); } @@ -1683,6 +1703,9 @@ const Type* elemtype = arytype->elem(); BasicType elembt = elemtype->array_element_basic_type(); Node* adr = array_element_address(ary, idx, elembt, arytype->size()); + if (elembt == T_NARROWOOP) { + elembt = T_OBJECT; // To satisfy switch in LoadNode::make() + } Node* ld = make_load(ctl, adr, elemtype, elembt, arytype, MemNode::unordered); return ld; }
--- a/src/share/vm/opto/graphKit.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/graphKit.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -517,23 +517,28 @@ // of volatile fields. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false) { + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from bottom_type return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(), - mo, control_dependency, require_atomic_access); + mo, control_dependency, require_atomic_access, + unaligned, mismatched); } Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false) { + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other make_load factory"); return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type), - mo, control_dependency, require_atomic_access); + mo, control_dependency, require_atomic_access, + unaligned, mismatched); } // This is the base version which is given an alias index. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false); + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false); // Create & transform a StoreNode and store the effect into the // parser's memory state. @@ -546,19 +551,24 @@ Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt, const TypePtr* adr_type, MemNode::MemOrd mo, - bool require_atomic_access = false) { + bool require_atomic_access = false, + bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other store_to_memory factory"); return store_to_memory(ctl, adr, val, bt, C->get_alias_index(adr_type), - mo, require_atomic_access); + mo, require_atomic_access, + unaligned, mismatched); } // This is the base version which is given alias index // Return the new StoreXNode Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt, int adr_idx, MemNode::MemOrd, - bool require_atomic_access = false); + bool require_atomic_access = false, + bool unaligned = false, + bool mismatched = false); // All in one pre-barrier, store, post_barrier @@ -581,7 +591,8 @@ const TypeOopPtr* val_type, BasicType bt, bool use_precise, - MemNode::MemOrd mo); + MemNode::MemOrd mo, + bool mismatched = false); Node* store_oop_to_object(Node* ctl, Node* obj, // containing obj @@ -612,7 +623,8 @@ const TypePtr* adr_type, Node* val, BasicType bt, - MemNode::MemOrd mo); + MemNode::MemOrd mo, + bool mismatched = false); // For the few case where the barriers need special help void pre_barrier(bool do_load, Node* ctl, @@ -656,7 +668,10 @@ // callee (with all arguments still on the stack). Node* null_check_receiver_before_call(ciMethod* callee) { assert(!callee->is_static(), "must be a virtual method"); - const int nargs = callee->arg_size(); + // Callsite signature can be different from actual method being called (i.e _linkTo* sites). + // Use callsite signature always. + ciMethod* declared_method = method()->get_method_at_bci(bci()); + const int nargs = declared_method->arg_size(); inc_sp(nargs); Node* n = null_check_receiver(); dec_sp(nargs);
--- a/src/share/vm/opto/idealKit.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/idealKit.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -368,7 +368,8 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access) { + MemNode::MemOrd mo, bool require_atomic_access, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory"); const TypePtr* adr_type = NULL; debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -379,6 +380,9 @@ } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } + if (mismatched) { + st->as_Store()->set_mismatched_access(); + } st = transform(st); set_memory(st, adr_idx);
--- a/src/share/vm/opto/idealKit.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/idealKit.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -227,7 +227,9 @@ BasicType bt, int adr_idx, MemNode::MemOrd mo, - bool require_atomic_access = false); + bool require_atomic_access = false, + bool mismatched = false + ); // Store a card mark ordered after store_oop Node* storeCM(Node* ctl,
--- a/src/share/vm/opto/ifnode.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/ifnode.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1081,8 +1081,9 @@ // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate)) - prev_dom = idom; + if ((unc_proj != NULL) && (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))) { + prev_dom = idom; + } // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses.
--- a/src/share/vm/opto/lcm.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/lcm.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -248,6 +248,14 @@ continue; } + // Check that node's control edge is not-null block's head or dominates it, + // otherwise we can't hoist it because there are other control dependencies. + Node* ctrl = mach->in(0); + if (ctrl != NULL && !(ctrl == not_null_block->head() || + get_block_for_node(ctrl)->dominates(not_null_block))) { + continue; + } + // check if the offset is not too high for implicit exception { intptr_t offset = 0; @@ -385,9 +393,12 @@ block->add_inst(best); map_node_to_block(best, block); - // Move the control dependence - if (best->in(0) && best->in(0) == old_block->head()) - best->set_req(0, block->head()); + // Move the control dependence if it is pinned to not-null block. + // Don't change it in other cases: NULL or dominating control. + if (best->in(0) == not_null_block->head()) { + // Set it to control edge of null check. + best->set_req(0, proj->in(0)->in(0)); + } // Check for flag-killing projections that also need to be hoisted // Should be DU safe because no edge updates. @@ -443,6 +454,18 @@ latency_from_uses(nul_chk); latency_from_uses(best); + + // insert anti-dependences to defs in this block + if (! best->needs_anti_dependence_check()) { + for (uint k = 1; k < block->number_of_nodes(); k++) { + Node *n = block->get_node(k); + if (n->needs_anti_dependence_check() && + n->in(LoadNode::Memory) == best->in(StoreNode::Memory)) { + // Found anti-dependent load + insert_anti_dependences(block, n); + } + } + } } @@ -1093,11 +1116,9 @@ Node *clone = block->get_node(j-1)->clone(); sb->insert_node(clone, 1); map_node_to_block(clone, sb); -#ifdef AARCH64 if (clone->needs_anti_dependence_check()) { insert_anti_dependences(sb, clone); } -#endif } }
--- a/src/share/vm/opto/library_call.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/library_call.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -230,7 +230,7 @@ // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); - bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile); + bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned); bool inline_unsafe_prefetch(bool is_native_ptr, bool is_store, bool is_static); static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); @@ -795,63 +795,63 @@ case vmIntrinsics::_indexOf: return inline_string_indexOf(); case vmIntrinsics::_equals: return inline_string_equals(); - case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile); - case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile); - case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile); - case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); - case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile); - - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile); - case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile); - case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile); - case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile); - case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile); - - case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile); - case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile); - case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile); - - case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile); - case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile); - case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile); - - case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile); - case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile); - case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile); - case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile); - case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile); - case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile); - case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile); - case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile); - case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile); - - case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile); - case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile); - case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile); - case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile); - case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile); - case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile); - case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile); - case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile); - case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile); + case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile, false); + case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false); + case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); + + case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile, false); + case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile, false); + case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + + case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false); + + case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile, false); + + case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile, false); + case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile, false); + case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile, false); + case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile, false); + case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile, false); + case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile, false); + case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile, false); + case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile, false); + case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile, false); + + case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile, false); + case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile, false); + case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile, false); + case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile, false); + case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile, false); + case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile, false); + case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile, false); + case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile, false); + case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile, false); case vmIntrinsics::_prefetchRead: return inline_unsafe_prefetch(!is_native_ptr, !is_store, !is_static); case vmIntrinsics::_prefetchWrite: return inline_unsafe_prefetch(!is_native_ptr, is_store, !is_static); @@ -2554,8 +2554,9 @@ return NULL; } -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile) { +bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { if (callee()->is_static()) return false; // caller must have the capability! + assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type"); #ifndef PRODUCT { @@ -2629,16 +2630,45 @@ val = is_store ? argument(3) : NULL; } + // Can base be NULL? Otherwise, always on-heap access. + bool can_access_non_heap = TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop)); + const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); + // Try to categorize the address. + Compile::AliasType* alias_type = C->alias_type(adr_type); + assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); + + if (alias_type->adr_type() == TypeInstPtr::KLASS || + alias_type->adr_type() == TypeAryPtr::RANGE) { + return false; // not supported + } + + bool mismatched = false; + BasicType bt = alias_type->basic_type(); + if (bt != T_ILLEGAL) { + assert(alias_type->adr_type()->is_oopptr(), "should be on-heap access"); + if (bt == T_BYTE && adr_type->isa_aryptr()) { + // Alias type doesn't differentiate between byte[] and boolean[]). + // Use address type to get the element type. + bt = adr_type->is_aryptr()->elem()->array_element_basic_type(); + } + if (bt == T_ARRAY || bt == T_NARROWOOP) { + // accessing an array field with getObject is not a mismatch + bt = T_OBJECT; + } + if ((bt == T_OBJECT) != (type == T_OBJECT)) { + // Don't intrinsify mismatched object accesses + return false; + } + mismatched = (bt != type); + } + + assert(!mismatched || alias_type->adr_type()->is_oopptr(), "off-heap access can't be mismatched"); + // First guess at the value type. const Type *value_type = Type::get_const_basic_type(type); - // Try to categorize the address. If it comes up as TypeJavaPtr::BOTTOM, - // there was not enough information to nail it down. - Compile::AliasType* alias_type = C->alias_type(adr_type); - assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); - // We will need memory barriers unless we can determine a unique // alias category for this reference. (Note: If for some reason // the barriers get omitted and the unsafe reference begins to "pollute" @@ -2701,7 +2731,7 @@ MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; // To be valid, unsafe loads may depend on other conditions than // the one that guards them: pin the Load node - Node* p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile); + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched); // load value switch (type) { case T_BOOLEAN: @@ -2747,12 +2777,12 @@ MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered; if (type != T_OBJECT ) { - (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile); + (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched); } else { // Possibly an oop being stored to Java heap or native memory - if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) { + if (!can_access_non_heap) { // oop to Java heap. - (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo); + (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched); } else { // We can't tell at compile time if we are storing in the Java heap or outside // of it. So we need to emit code to conditionally do the proper type of @@ -2764,11 +2794,11 @@ __ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); { // Sync IdealKit and graphKit. sync_kit(ideal); - Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo); + Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched); // Update IdealKit memory. __ sync_kit(this); } __ else_(); { - __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile); + __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched); } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); @@ -2939,12 +2969,6 @@ newval = argument(4); // type: oop, int, or long } - // Null check receiver. - receiver = null_check(receiver); - if (stopped()) { - return true; - } - // Build field offset expression. // We currently rely on the cookies produced by Unsafe.xxxFieldOffset // to be plain byte offsets, which are also the same as those accepted @@ -2955,11 +2979,18 @@ Node* adr = make_unsafe_address(base, offset); const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); + Compile::AliasType* alias_type = C->alias_type(adr_type); + BasicType bt = alias_type->basic_type(); + if (bt != T_ILLEGAL && + ((bt == T_OBJECT || bt == T_ARRAY) != (type == T_OBJECT))) { + // Don't intrinsify mismatched object accesses. + return false; + } + // For CAS, unlike inline_unsafe_access, there seems no point in // trying to refine types. Just use the coarse types here. + assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); const Type *value_type = Type::get_const_basic_type(type); - Compile::AliasType* alias_type = C->alias_type(adr_type); - assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); if (kind == LS_xchg && type == T_OBJECT) { const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); @@ -2968,6 +2999,12 @@ } } + // Null check receiver. + receiver = null_check(receiver); + if (stopped()) { + return true; + } + int alias_idx = C->get_alias_index(adr_type); // Memory-model-wise, a LoadStore acts like a little synchronized @@ -6480,7 +6517,20 @@ //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { +#ifdef PPC64 + // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. + // Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. + // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. + // The ppc64 stubs of encryption and decryption use the same round keys (sessionK[0]). + Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I", /*is_exact*/ false); + assert (objSessionK != NULL, "wrong version of com.sun.crypto.provider.AESCrypt"); + if (objSessionK == NULL) { + return (Node *) NULL; + } + Node* objAESCryptKey = load_array_element(control(), objSessionK, intcon(0), TypeAryPtr::OOPS); +#else Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false); +#endif // PPC64 assert (objAESCryptKey != NULL, "wrong version of com.sun.crypto.provider.AESCrypt"); if (objAESCryptKey == NULL) return (Node *) NULL;
--- a/src/share/vm/opto/loopTransform.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/loopTransform.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -2714,6 +2714,11 @@ return false; } + Node* exit = head->loopexit()->proj_out(0); + if (exit == NULL) { + return false; + } + #ifndef PRODUCT if (TraceLoopOpts) { tty->print("ArrayFill "); @@ -2831,7 +2836,6 @@ */ // Redirect the old control and memory edges that are outside the loop. - Node* exit = head->loopexit()->proj_out(0); // Sometimes the memory phi of the head is used as the outgoing // state of the loop. It's safe in this case to replace it with the // result_mem.
--- a/src/share/vm/opto/macro.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/macro.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -401,7 +401,7 @@ for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) { Node* phi = region->fast_out(k); if (phi->is_Phi() && phi != mem && - phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) { + phi->as_Phi()->is_same_inst_field(phi_type, (int)mem->_idx, instance_id, alias_idx, offset)) { return phi; } } @@ -420,7 +420,7 @@ GrowableArray <Node *> values(length, length, NULL, false); // create a new Phi for the value - PhiNode *phi = new (C) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset); + PhiNode *phi = new (C) PhiNode(mem->in(0), phi_type, NULL, mem->_idx, instance_id, alias_idx, offset); transform_later(phi); value_phis->push(phi, mem->_idx);
--- a/src/share/vm/opto/matcher.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/matcher.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1022,7 +1022,7 @@ if (C->failing()) return NULL; if (m == NULL) { Matcher::soft_match_failure(); return NULL; } } else { // Nothing the matcher cares about - if( n->is_Proj() && n->in(0)->is_Multi()) { // Projections? + if (n->is_Proj() && n->in(0) != NULL && n->in(0)->is_Multi()) { // Projections? // Convert to machine-dependent projection m = n->in(0)->as_Multi()->match( n->as_Proj(), this ); #ifdef ASSERT @@ -1659,6 +1659,7 @@ // Build the object to represent this state & prepare for recursive calls MachNode *mach = s->MachNodeGenerator( rule, C ); + guarantee(mach != NULL, "Missing MachNode"); mach->_opnds[0] = s->MachOperGenerator( _reduceOp[rule], C ); assert( mach->_opnds[0] != NULL, "Missing result operand" ); Node *leaf = s->_leaf;
--- a/src/share/vm/opto/memnode.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/memnode.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -67,8 +67,15 @@ dump_adr_type(this, _adr_type, st); Compile* C = Compile::current(); - if( C->alias_type(_adr_type)->is_volatile() ) + if (C->alias_type(_adr_type)->is_volatile()) { st->print(" Volatile!"); + } + if (_unaligned_access) { + st->print(" unaligned"); + } + if (_mismatched_access) { + st->print(" mismatched"); + } } void MemNode::dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st) { @@ -1149,13 +1156,16 @@ // Use _idx of address base (could be Phi node) for boxed values. intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(in(Address), phase, ignore); + if (base == NULL) { + return this; + } this_iid = base->_idx; } const Type* this_type = bottom_type(); for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { Node* phi = region->fast_out(i); if (phi->is_Phi() && phi != mem && - phi->as_Phi()->is_same_inst_field(this_type, this_iid, this_index, this_offset)) { + phi->as_Phi()->is_same_inst_field(this_type, (int)mem->_idx, this_iid, this_index, this_offset)) { return phi; } } @@ -1400,7 +1410,7 @@ this_iid = base->_idx; } PhaseIterGVN* igvn = phase->is_IterGVN(); - Node* phi = new (C) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); + Node* phi = new (C) PhiNode(region, this_type, NULL, mem->_idx, this_iid, this_index, this_offset); for (uint i = 1; i < region->req(); i++) { Node* x; Node* the_clone = NULL; @@ -3324,6 +3334,9 @@ // within the initialized memory. intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape) { const int FAIL = 0; + if (st->is_unaligned_access()) { + return FAIL; + } if (st->req() != MemNode::ValueIn + 1) return FAIL; // an inscrutable StoreNode (card mark?) Node* ctl = st->in(MemNode::Control); @@ -4027,9 +4040,10 @@ // if it is the last unused 4 bytes of an instance, forget about it intptr_t size_limit = phase->find_intptr_t_con(size_in_bytes, max_jint); if (zeroes_done + BytesPerLong >= size_limit) { - assert(allocation() != NULL, ""); - if (allocation()->Opcode() == Op_Allocate) { - Node* klass_node = allocation()->in(AllocateNode::KlassNode); + AllocateNode* alloc = allocation(); + assert(alloc != NULL, "must be present"); + if (alloc != NULL && alloc->Opcode() == Op_Allocate) { + Node* klass_node = alloc->in(AllocateNode::KlassNode); ciKlass* k = phase->type(klass_node)->is_klassptr()->klass(); if (zeroes_done == k->layout_helper()) zeroes_done = size_limit;
--- a/src/share/vm/opto/memnode.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/memnode.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -39,11 +39,14 @@ //------------------------------MemNode---------------------------------------- // Load or Store, possibly throwing a NULL pointer exception class MemNode : public Node { +private: + bool _unaligned_access; // Unaligned access from unsafe + bool _mismatched_access; // Mismatched access from unsafe: byte read in integer array for instance protected: #ifdef ASSERT const TypePtr* _adr_type; // What kind of memory is being addressed? #endif - virtual uint size_of() const; // Size is bigger (ASSERT only) + virtual uint size_of() const; public: enum { Control, // When is it safe to do this load? Memory, // Chunk of memory is being loaded from @@ -57,17 +60,17 @@ } MemOrd; protected: MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at ) - : Node(c0,c1,c2 ) { + : Node(c0,c1,c2 ), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3 ) - : Node(c0,c1,c2,c3) { + : Node(c0,c1,c2,c3), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3, Node *c4) - : Node(c0,c1,c2,c3,c4) { + : Node(c0,c1,c2,c3,c4), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } @@ -129,6 +132,11 @@ // the given memory state? (The state may or may not be in(Memory).) Node* can_see_stored_value(Node* st, PhaseTransform* phase) const; + void set_unaligned_access() { _unaligned_access = true; } + bool is_unaligned_access() const { return _unaligned_access; } + void set_mismatched_access() { _mismatched_access = true; } + bool is_mismatched_access() const { return _mismatched_access; } + #ifndef PRODUCT static void dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st); virtual void dump_spec(outputStream *st) const;
--- a/src/share/vm/opto/phaseX.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/phaseX.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -481,6 +481,8 @@ uint current_idx = 0; // The current new node ID. Incremented after every assignment. for (uint i = 0; i < _useful.size(); i++) { Node* n = _useful.at(i); + // Sanity check that fails if we ever decide to execute this phase after EA + assert(!n->is_Phi() || n->as_Phi()->inst_mem_id() == -1, "should not be linked to data Phi"); const Type* type = gvn->type_or_null(n); new_type_array.map(current_idx, type); @@ -1378,6 +1380,18 @@ i -= num_edges; // we deleted 1 or more copies of this edge } + // Search for instance field data PhiNodes in the same region pointing to the old + // memory PhiNode and update their instance memory ids to point to the new node. + if (old->is_Phi() && old->as_Phi()->type()->has_memory() && old->in(0) != NULL) { + Node* region = old->in(0); + for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { + PhiNode* phi = region->fast_out(i)->isa_Phi(); + if (phi != NULL && phi->inst_mem_id() == (int)old->_idx) { + phi->set_inst_mem_id((int)nn->_idx); + } + } + } + // Smash all inputs to 'old', isolating him completely Node *temp = new (C) Node(1); temp->init_req(0,nn); // Add a use to nn to prevent him from dying
--- a/src/share/vm/opto/stringopts.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/stringopts.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -891,8 +891,9 @@ ctrl_path.push(cn); ctrl_path.push(cn->proj_out(0)); ctrl_path.push(cn->proj_out(0)->unique_out()); - if (cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0) != NULL) { - ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0)); + Node* catchproj = cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0); + if (catchproj != NULL) { + ctrl_path.push(catchproj); } } else { ShouldNotReachHere();
--- a/src/share/vm/opto/type.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/opto/type.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -209,11 +209,11 @@ static int cmp( const Type *const t1, const Type *const t2 ); // Test for higher or equal in lattice // Variant that drops the speculative part of the types - int higher_equal(const Type *t) const { + bool higher_equal(const Type *t) const { return !cmp(meet(t),t->remove_speculative()); } // Variant that keeps the speculative part of the types - int higher_equal_speculative(const Type *t) const { + bool higher_equal_speculative(const Type *t) const { return !cmp(meet_speculative(t),t); } @@ -882,7 +882,7 @@ // If not InstanceTop or InstanceBot, indicates that this is // a particular instance of this type which is distinct. - // This is the the node index of the allocation node creating this instance. + // This is the node index of the allocation node creating this instance. int _instance_id; // Extra type information profiling gave us. We propagate it the
--- a/src/share/vm/prims/jni.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jni.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -5129,6 +5129,7 @@ run_unit_test(TestKlass_test()); run_unit_test(Test_linked_list()); run_unit_test(TestChunkedList_test()); + run_unit_test(ObjectMonitor::sanity_checks()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif
--- a/src/share/vm/prims/jvm.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jvm.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -643,7 +643,7 @@ // This can safepoint and redefine method, so need both new_obj and method // in a handle, for two different reasons. new_obj can move, method can be // deleted if nothing is using it on the stack. - m->method_holder()->add_member_name(new_obj()); + m->method_holder()->add_member_name(new_obj(), false); } } @@ -1356,7 +1356,7 @@ Method* m_oop = object->klass()->uncached_lookup_method( vmSymbols::run_method_name(), vmSymbols::void_object_signature(), - Klass::normal); + Klass::find_overpass); methodHandle m (THREAD, m_oop); if (m.is_null() || !m->is_method() || !m()->is_public() || m()->is_static()) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "No run method");
--- a/src/share/vm/prims/jvmtiEnv.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jvmtiEnv.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1000,8 +1000,9 @@ GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true); - uint32_t debug_bits = 0; - if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == calling_thread) { err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list); } else { // JVMTI get monitors info at safepoint. Do not require target thread to @@ -1045,8 +1046,9 @@ GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true); - uint32_t debug_bits = 0; - if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == calling_thread) { err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list); } else { // JVMTI get owned monitors info at safepoint. Do not require target thread to @@ -1087,9 +1089,11 @@ jvmtiError JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_ptr) { jvmtiError err = JVMTI_ERROR_NONE; - uint32_t debug_bits = 0; JavaThread* calling_thread = JavaThread::current(); - if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { + + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == calling_thread) { err = get_current_contended_monitor(calling_thread, java_thread, monitor_ptr); } else { // get contended monitor information at safepoint. @@ -1298,8 +1302,10 @@ jvmtiError JvmtiEnv::GetStackTrace(JavaThread* java_thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo* frame_buffer, jint* count_ptr) { jvmtiError err = JVMTI_ERROR_NONE; - uint32_t debug_bits = 0; - if (is_thread_fully_suspended(java_thread, true, &debug_bits)) { + + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == JavaThread::current()) { err = get_stack_trace(java_thread, start_depth, max_frame_count, frame_buffer, count_ptr); } else { // JVMTI get stack trace at safepoint. Do not require target thread to
--- a/src/share/vm/prims/jvmtiEnvBase.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jvmtiEnvBase.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -356,8 +356,12 @@ } VMOp_Type type() const { return VMOp_GetOwnedMonitorInfo; } void doit() { - ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread, - _owned_monitors_list); + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + if (Threads::includes(_java_thread) && !_java_thread->is_exiting() + && _java_thread->threadObj() != NULL) { + _result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread, + _owned_monitors_list); + } } jvmtiError result() { return _result; } }; @@ -439,9 +443,13 @@ jvmtiError result() { return _result; } VMOp_Type type() const { return VMOp_GetStackTrace; } void doit() { - _result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread, - _start_depth, _max_count, - _frame_buffer, _count_ptr); + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + if (Threads::includes(_java_thread) && !_java_thread->is_exiting() + && _java_thread->threadObj() != NULL) { + _result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread, + _start_depth, _max_count, + _frame_buffer, _count_ptr); + } } };
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -42,6 +42,7 @@ #include "runtime/deoptimization.hpp" #include "runtime/relocator.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/events.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -172,6 +173,9 @@ // Free os::malloc allocated memory. os::free(_scratch_classes); + // Reset the_class_oop to null for error printing. + _the_class_oop = NULL; + if (RC_TRACE_ENABLED(0x00000004)) { // Used to have separate timers for "doit" and "all", but the timer // overhead skewed the measurements. @@ -4096,6 +4100,13 @@ java_lang_Class::classRedefinedCount(the_class_mirror), os::available_memory() >> 10)); + { + ResourceMark rm(THREAD); + Events::log_redefinition(THREAD, "redefined class name=%s, count=%d", + the_class->external_name(), + java_lang_Class::classRedefinedCount(the_class_mirror)); + + } RC_TIMER_STOP(_timer_rsc_phase2); } // end redefine_single_class() @@ -4240,3 +4251,11 @@ tty->cr(); } } + +void VM_RedefineClasses::print_on_error(outputStream* st) const { + VM_Operation::print_on_error(st); + if (_the_class_oop != NULL) { + ResourceMark rm; + st->print_cr(", redefining class %s", _the_class_oop->external_name()); + } +}
--- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -538,5 +538,8 @@ static unsigned char * get_cached_class_file_bytes(JvmtiCachedClassFileData *cache) { return cache == NULL ? NULL : cache->data; } + + // Error printing + void print_on_error(outputStream* st) const; }; #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP
--- a/src/share/vm/prims/methodHandles.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/methodHandles.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -173,7 +173,7 @@ return NULL; } -oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { +oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, bool intern) { assert(info.resolved_appendix().is_null(), "only normal methods here"); methodHandle m = info.resolved_method(); KlassHandle m_klass = m->method_holder(); @@ -270,13 +270,7 @@ // If relevant, the vtable or itable value is stored as vmindex. // This is done eagerly, since it is readily available without // constructing any new objects. - // TO DO: maybe intern mname_oop - if (m->method_holder()->add_member_name(mname)) { - return mname(); - } else { - // Redefinition caused this to fail. Return NULL (and an exception?) - return NULL; - } + return m->method_holder()->add_member_name(mname, intern); } oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) { @@ -917,7 +911,9 @@ if (!java_lang_invoke_MemberName::is_instance(result())) return -99; // caller bug! CallInfo info(m); - oop saved = MethodHandles::init_method_MemberName(result, info); + // Since this is going through the methods to create MemberNames, don't search + // for matching methods already in the table + oop saved = MethodHandles::init_method_MemberName(result, info, /*intern*/false); if (saved != result()) results->obj_at_put(rfill-1, saved); // show saved instance to user } else if (++overflow >= overflow_limit) { @@ -949,9 +945,34 @@ } } -void MemberNameTable::add_member_name(jweak mem_name_wref) { +oop MemberNameTable::add_member_name(jweak mem_name_wref) { assert_locked_or_safepoint(MemberNameTable_lock); this->push(mem_name_wref); + return JNIHandles::resolve(mem_name_wref); +} + +oop MemberNameTable::find_or_add_member_name(jweak mem_name_wref) { + assert_locked_or_safepoint(MemberNameTable_lock); + oop new_mem_name = JNIHandles::resolve(mem_name_wref); + + // Find matching member name in the list. + // This is linear because these are short lists. + int len = this->length(); + int new_index = len; + for (int idx = 0; idx < len; idx++) { + oop mname = JNIHandles::resolve(this->at(idx)); + if (mname == NULL) { + new_index = idx; + continue; + } + if (java_lang_invoke_MemberName::equals(new_mem_name, mname)) { + JNIHandles::destroy_weak_global(mem_name_wref); + return mname; + } + } + // Not found, push the new one, or reuse empty slot + this->at_put_grow(new_index, mem_name_wref); + return new_mem_name; } #if INCLUDE_JVMTI
--- a/src/share/vm/prims/methodHandles.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/methodHandles.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -65,7 +65,7 @@ static Handle new_MemberName(TRAPS); // must be followed by init_MemberName static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target static oop init_field_MemberName(Handle mname_h, fieldDescriptor& fd, bool is_setter = false); - static oop init_method_MemberName(Handle mname_h, CallInfo& info); + static oop init_method_MemberName(Handle mname_h, CallInfo& info, bool intern = true); static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true); static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig, int mflags, KlassHandle caller, @@ -244,7 +244,8 @@ public: MemberNameTable(int methods_cnt); ~MemberNameTable(); - void add_member_name(jweak mem_name_ref); + oop add_member_name(jweak mem_name_ref); + oop find_or_add_member_name(jweak mem_name_ref); #if INCLUDE_JVMTI // RedefineClasses() API support:
--- a/src/share/vm/prims/nativeLookup.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/nativeLookup.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -408,7 +408,7 @@ // Find method and invoke standard lookup methodHandle method (THREAD, - klass->uncached_lookup_method(m_name, s_name, Klass::normal)); + klass->uncached_lookup_method(m_name, s_name, Klass::find_overpass)); address result = lookup(method, in_base_library, CATCH); assert(in_base_library, "must be in basic library"); guarantee(result != NULL, "must be non NULL");
--- a/src/share/vm/prims/unsafe.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/prims/unsafe.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1033,14 +1033,6 @@ } UNSAFE_END -static jobject get_class_loader(JNIEnv* env, jclass cls) { - if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) { - return NULL; - } - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); - oop loader = k->class_loader(); - return JNIHandles::make_local(env, loader); -} UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length)) UnsafeWrapper("Unsafe_DefineClass"); @@ -1049,7 +1041,7 @@ int depthFromDefineClass0 = 1; jclass caller = JVM_GetCallerClass(env, depthFromDefineClass0); - jobject loader = (caller == NULL) ? NULL : get_class_loader(env, caller); + jobject loader = (caller == NULL) ? NULL : JVM_GetClassLoader(env, caller); jobject pd = (caller == NULL) ? NULL : JVM_GetProtectionDomain(env, caller); return Unsafe_DefineClass_impl(env, name, data, offset, length, loader, pd);
--- a/src/share/vm/runtime/fieldDescriptor.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/fieldDescriptor.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -106,6 +106,7 @@ bool is_field_access_watched() const { return access_flags().is_field_access_watched(); } bool is_field_modification_watched() const { return access_flags().is_field_modification_watched(); } + bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); } bool has_generic_signature() const { return access_flags().field_has_generic_signature(); } void set_is_field_access_watched(const bool value) { @@ -118,6 +119,11 @@ update_klass_field_access_flag(); } + void set_has_initialized_final_update(const bool value) { + _access_flags.set_has_field_initialized_final_update(value); + update_klass_field_access_flag(); + } + // Initialization void reinitialize(InstanceKlass* ik, int index);
--- a/src/share/vm/runtime/objectMonitor.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/objectMonitor.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -2529,6 +2529,10 @@ SETKNOB(FastHSSEC) ; #undef SETKNOB + if (Knob_Verbose) { + sanity_checks(); + } + if (os::is_MP()) { BackOffMask = (1 << Knob_SpinBackOff) - 1 ; if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ; @@ -2549,6 +2553,66 @@ InitDone = 1 ; } +void ObjectMonitor::sanity_checks() { + int error_cnt = 0; + int warning_cnt = 0; + bool verbose = Knob_Verbose != 0 NOT_PRODUCT(|| VerboseInternalVMTests); + + if (verbose) { + tty->print_cr("INFO: sizeof(ObjectMonitor)=" SIZE_FORMAT, + sizeof(ObjectMonitor)); + } + + uint cache_line_size = VM_Version::L1_data_cache_line_size(); + if (verbose) { + tty->print_cr("INFO: L1_data_cache_line_size=%u", cache_line_size); + } + + ObjectMonitor dummy; + u_char *addr_begin = (u_char*)&dummy; + u_char *addr_header = (u_char*)&dummy._header; + u_char *addr_owner = (u_char*)&dummy._owner; + + uint offset_header = (uint)(addr_header - addr_begin); + if (verbose) tty->print_cr("INFO: offset(_header)=%u", offset_header); + + uint offset_owner = (uint)(addr_owner - addr_begin); + if (verbose) tty->print_cr("INFO: offset(_owner)=%u", offset_owner); + + if ((uint)(addr_header - addr_begin) != 0) { + tty->print_cr("ERROR: offset(_header) must be zero (0)."); + error_cnt++; + } + + if (cache_line_size != 0) { + // We were able to determine the L1 data cache line size so + // do some cache line specific sanity checks + + if ((offset_owner - offset_header) < cache_line_size) { + tty->print_cr("WARNING: the _header and _owner fields are closer " + "than a cache line which permits false sharing."); + warning_cnt++; + } + + if ((sizeof(ObjectMonitor) % cache_line_size) != 0) { + tty->print_cr("WARNING: ObjectMonitor size is not a multiple of " + "a cache line which permits false sharing."); + warning_cnt++; + } + } + + ObjectSynchronizer::sanity_checks(verbose, cache_line_size, &error_cnt, + &warning_cnt); + + if (verbose || error_cnt != 0 || warning_cnt != 0) { + tty->print_cr("INFO: error_cnt=%d", error_cnt); + tty->print_cr("INFO: warning_cnt=%d", warning_cnt); + } + + guarantee(error_cnt == 0, + "Fatal error(s) found in ObjectMonitor::sanity_checks()"); +} + #ifndef PRODUCT void ObjectMonitor::verify() { }
--- a/src/share/vm/runtime/objectMonitor.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/objectMonitor.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -189,6 +189,8 @@ bool check(TRAPS); // true if the thread owns the monitor. void check_slow(TRAPS); void clear(); + static void sanity_checks(); // public for -XX:+ExecuteInternalVMTests + // in PRODUCT for -XX:SyncKnobs=Verbose=1 #ifndef PRODUCT void verify(); void print(); @@ -234,8 +236,6 @@ // WARNING: this must be the very first word of ObjectMonitor // This means this class can't use any virtual member functions. - // TODO-FIXME: assert that offsetof(_header) is 0 or get rid of the - // implicit 0 offset in emitted code. volatile markOop _header; // displaced object header word - mark void* volatile _object; // backward object pointer - strong root
--- a/src/share/vm/runtime/sharedRuntime.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -554,7 +554,7 @@ CodeBlob *cb = CodeCache::find_blob(pc); // Should be an nmethod - assert( cb && cb->is_nmethod(), "safepoint polling: pc must refer to an nmethod" ); + guarantee(cb != NULL && cb->is_nmethod(), "safepoint polling: pc must refer to an nmethod"); // Look up the relocation information assert( ((nmethod*)cb)->is_at_poll_or_poll_return(pc), @@ -1717,7 +1717,7 @@ // ask me how I know this... CodeBlob* cb = CodeCache::find_blob(caller_pc); - if (!cb->is_nmethod() || entry_point == moop->get_c2i_entry()) { + if (cb == NULL || !cb->is_nmethod() || entry_point == moop->get_c2i_entry()) { return; } @@ -1768,7 +1768,7 @@ if (destination != entry_point) { CodeBlob* callee = CodeCache::find_blob(destination); // callee == cb seems weird. It means calling interpreter thru stub. - if (callee == cb || callee->is_adapter_blob()) { + if (callee != NULL && (callee == cb || callee->is_adapter_blob())) { // static call or optimized virtual if (TraceCallFixup) { tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
--- a/src/share/vm/runtime/synchronizer.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/synchronizer.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -437,19 +437,22 @@ // Hash Code handling // // Performance concern: -// OrderAccess::storestore() calls release() which STs 0 into the global volatile -// OrderAccess::Dummy variable. This store is unnecessary for correctness. -// Many threads STing into a common location causes considerable cache migration -// or "sloshing" on large SMP system. As such, I avoid using OrderAccess::storestore() -// until it's repaired. In some cases OrderAccess::fence() -- which incurs local -// latency on the executing processor -- is a better choice as it scales on SMP -// systems. See http://blogs.sun.com/dave/entry/biased_locking_in_hotspot for a -// discussion of coherency costs. Note that all our current reference platforms -// provide strong ST-ST order, so the issue is moot on IA32, x64, and SPARC. +// OrderAccess::storestore() calls release() which at one time stored 0 +// into the global volatile OrderAccess::dummy variable. This store was +// unnecessary for correctness. Many threads storing into a common location +// causes considerable cache migration or "sloshing" on large SMP systems. +// As such, I avoided using OrderAccess::storestore(). In some cases +// OrderAccess::fence() -- which incurs local latency on the executing +// processor -- is a better choice as it scales on SMP systems. +// +// See http://blogs.oracle.com/dave/entry/biased_locking_in_hotspot for +// a discussion of coherency costs. Note that all our current reference +// platforms provide strong ST-ST order, so the issue is moot on IA32, +// x64, and SPARC. // // As a general policy we use "volatile" to control compiler-based reordering -// and explicit fences (barriers) to control for architectural reordering performed -// by the CPU(s) or platform. +// and explicit fences (barriers) to control for architectural reordering +// performed by the CPU(s) or platform. struct SharedGlobals { // These are highly shared mostly-read variables. @@ -1636,7 +1639,55 @@ } //------------------------------------------------------------------------------ -// Non-product code +// Debugging code + +void ObjectSynchronizer::sanity_checks(const bool verbose, + const uint cache_line_size, + int *error_cnt_ptr, + int *warning_cnt_ptr) { + u_char *addr_begin = (u_char*)&GVars; + u_char *addr_stwRandom = (u_char*)&GVars.stwRandom; + u_char *addr_hcSequence = (u_char*)&GVars.hcSequence; + + if (verbose) { + tty->print_cr("INFO: sizeof(SharedGlobals)=" SIZE_FORMAT, + sizeof(SharedGlobals)); + } + + uint offset_stwRandom = (uint)(addr_stwRandom - addr_begin); + if (verbose) tty->print_cr("INFO: offset(stwRandom)=%u", offset_stwRandom); + + uint offset_hcSequence = (uint)(addr_hcSequence - addr_begin); + if (verbose) { + tty->print_cr("INFO: offset(_hcSequence)=%u", offset_hcSequence); + } + + if (cache_line_size != 0) { + // We were able to determine the L1 data cache line size so + // do some cache line specific sanity checks + + if (offset_stwRandom < cache_line_size) { + tty->print_cr("WARNING: the SharedGlobals.stwRandom field is closer " + "to the struct beginning than a cache line which permits " + "false sharing."); + (*warning_cnt_ptr)++; + } + + if ((offset_hcSequence - offset_stwRandom) < cache_line_size) { + tty->print_cr("WARNING: the SharedGlobals.stwRandom and " + "SharedGlobals.hcSequence fields are closer than a cache " + "line which permits false sharing."); + (*warning_cnt_ptr)++; + } + + if ((sizeof(SharedGlobals) - offset_hcSequence) < cache_line_size) { + tty->print_cr("WARNING: the SharedGlobals.hcSequence field is closer " + "to the struct end than a cache line which permits false " + "sharing."); + (*warning_cnt_ptr)++; + } + } +} #ifndef PRODUCT
--- a/src/share/vm/runtime/synchronizer.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/synchronizer.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -121,6 +121,9 @@ static void oops_do(OopClosure* f); // debugging + static void sanity_checks(const bool verbose, + const unsigned int cache_line_size, + int *error_cnt_ptr, int *warning_cnt_ptr); static void verify() PRODUCT_RETURN; static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
--- a/src/share/vm/runtime/vmStructs.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/vmStructs.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -887,7 +887,7 @@ nonstatic_field(nmethod, _stack_traversal_mark, long) \ nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, int) \ - nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ + volatile_nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \
--- a/src/share/vm/runtime/vm_operations.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/vm_operations.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -183,7 +183,7 @@ static const char* mode_to_string(Mode mode); // Debugging - void print_on_error(outputStream* st) const; + virtual void print_on_error(outputStream* st) const; const char* name() const { return _names[type()]; } static const char* name(int type) { assert(type >= 0 && type < VMOp_Terminating, "invalid VM operation type");
--- a/src/share/vm/runtime/vm_version.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/vm_version.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -53,6 +53,7 @@ bool Abstract_VM_Version::_supports_atomic_getadd4 = false; bool Abstract_VM_Version::_supports_atomic_getadd8 = false; unsigned int Abstract_VM_Version::_logical_processors_per_package = 1U; +unsigned int Abstract_VM_Version::_L1_data_cache_line_size = 0; int Abstract_VM_Version::_reserve_for_allocation_prefetch = 0; #ifndef HOTSPOT_RELEASE_VERSION
--- a/src/share/vm/runtime/vm_version.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/runtime/vm_version.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -42,6 +42,7 @@ static bool _supports_atomic_getadd4; static bool _supports_atomic_getadd8; static unsigned int _logical_processors_per_package; + static unsigned int _L1_data_cache_line_size; static int _vm_major_version; static int _vm_minor_version; static int _vm_build_number; @@ -114,6 +115,10 @@ return _logical_processors_per_package; } + static unsigned int L1_data_cache_line_size() { + return _L1_data_cache_line_size; + } + // Need a space at the end of TLAB for prefetch instructions // which may fault when accessing memory outside of heap. static int reserve_for_allocation_prefetch() {
--- a/src/share/vm/services/attachListener.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/services/attachListener.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,13 +271,17 @@ // set a uintx global flag using value from AttachOperation static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) { uintx value; - const char* arg1; - if ((arg1 = op->arg(1)) != NULL) { - int n = sscanf(arg1, UINTX_FORMAT, &value); - if (n != 1) { - out->print_cr("flag value must be an unsigned integer"); - return JNI_ERR; - } + + const char* arg1 = op->arg(1); + if (arg1 == NULL) { + out->print_cr("flag value must be specified"); + return JNI_ERR; + } + + int n = sscanf(arg1, UINTX_FORMAT, &value); + if (n != 1) { + out->print_cr("flag value must be an unsigned integer"); + return JNI_ERR; } if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
--- a/src/share/vm/utilities/accessFlags.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/utilities/accessFlags.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -76,11 +76,12 @@ // These bits must not conflict with any other field-related access flags // (e.g., ACC_ENUM). // Note that the class-related ACC_ANNOTATION bit conflicts with these flags. - JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI - JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI - JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT - JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED - JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature + JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI + JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI + JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT + JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED and JVM_ACC_SUPER + JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE = 0x00000100, // (static) final field updated outside (class) initializer, same as JVM_ACC_NATIVE + JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED | JVM_ACC_FIELD_MODIFICATION_WATCHED | @@ -150,6 +151,8 @@ bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; } bool is_field_modification_watched() const { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; } + bool has_field_initialized_final_update() const + { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; } bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; } bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; } bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; } @@ -229,6 +232,15 @@ atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED); } } + + void set_has_field_initialized_final_update(const bool value) { + if (value) { + atomic_set_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); + } else { + atomic_clear_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); + } + } + void set_field_has_generic_signature() { atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
--- a/src/share/vm/utilities/events.cpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/utilities/events.cpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -36,6 +36,7 @@ EventLog* Events::_logs = NULL; StringEventLog* Events::_messages = NULL; StringEventLog* Events::_exceptions = NULL; +StringEventLog* Events::_redefinitions = NULL; StringEventLog* Events::_deopt_messages = NULL; EventLog::EventLog() { @@ -65,6 +66,7 @@ if (LogEvents) { _messages = new StringEventLog("Events"); _exceptions = new StringEventLog("Internal exceptions"); + _redefinitions = new StringEventLog("Classes redefined"); _deopt_messages = new StringEventLog("Deoptimization events"); } }
--- a/src/share/vm/utilities/events.hpp Thu Nov 02 06:16:13 2017 +0000 +++ b/src/share/vm/utilities/events.hpp Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -186,6 +186,9 @@ // Deoptization related messages static StringEventLog* _deopt_messages; + // Redefinition related messages + static StringEventLog* _redefinitions; + public: static void print_all(outputStream* out); @@ -198,6 +201,8 @@ // Log exception related message static void log_exception(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); + static void log_redefinition(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); + static void log_deopt_message(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); // Register default loggers @@ -222,6 +227,15 @@ } } +inline void Events::log_redefinition(Thread* thread, const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + _redefinitions->logv(thread, format, ap); + va_end(ap); + } +} + inline void Events::log_deopt_message(Thread* thread, const char* format, ...) { if (LogEvents) { va_list ap;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/c1/TestUnresolvedField.jasm Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +public class compiler/c1/TestUnresolvedField version 52:0 { + public static Method testGetField:"()V" stack 1 locals 1 { + aconst_null; + getfield Field T.f:I; // T does not exist + return; + } + + public static Method testPutField:"()V" stack 2 locals 1 { + aconst_null; + iconst_0; + putfield Field T.f:I; // T does not exist + return; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/c1/TestUnresolvedFieldMain.java Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8173373 + * @compile TestUnresolvedField.jasm + * @run main/othervm -XX:TieredStopAtLevel=1 -Xcomp + * -XX:CompileCommand=compileonly,compiler.c1.TestUnresolvedField::test* + * compiler.c1.TestUnresolvedFieldMain + */ + +package compiler.c1; + +public class TestUnresolvedFieldMain { + public static void main(String[] args) { + try { + TestUnresolvedField.testGetField(); + } catch (java.lang.NoClassDefFoundError error) { + // Expected + } + try { + TestUnresolvedField.testPutField(); + } catch (java.lang.NoClassDefFoundError error) { + // Expected + } + } +}
--- a/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Dec 07 02:46:58 2017 +0000 @@ -61,6 +61,7 @@ String[] vmOpts = new String[] { "-Xbootclasspath/p:" + testClasses, "-Xcomp", + "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-VerifyDependencies", "-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize", "-XX:CompileOnly=Object::finalizeObject",
--- a/test/compiler/jsr292/NullConstantReceiver.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/compiler/jsr292/NullConstantReceiver.java Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,8 +23,11 @@ /** * @test - * @bug 8059556 + * @bug 8059556 8158639 8164508 + * * @run main/othervm -Xbatch NullConstantReceiver + * @run main/othervm -Xbatch -XX:CompileCommand=exclude,*::run NullConstantReceiver + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*::run NullConstantReceiver */ import java.lang.invoke.MethodHandle;
--- a/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java Thu Dec 07 02:46:58 2017 +0000 @@ -24,6 +24,7 @@ /** * @test * @bug 8161147 + * @requires vm.flavor == "server" * @summary Safepoint on backedge breaks UseCountedLoopSafepoints * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+UseCountedLoopSafepoints TestCountedLoopSafepointBackedge *
--- a/test/compiler/loopopts/TestLoopPeeling.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/compiler/loopopts/TestLoopPeeling.java Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,10 +23,16 @@ /* * @test - * @bug 8078262 + * @bug 8078262 8177095 * @summary Tests correct dominator information after loop peeling. - * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopPeeling::test* TestLoopPeeling + * + * @run main/othervm -Xcomp + * -XX:CompileCommand=compileonly,compiler.loopopts.TestLoopPeeling::test* + * compiler.loopopts.TestLoopPeeling */ + +package compiler.loopopts; + public class TestLoopPeeling { public int[] array = new int[100]; @@ -34,14 +40,16 @@ public static void main(String args[]) { TestLoopPeeling test = new TestLoopPeeling(); try { - test.testArrayAccess(0, 1); + test.testArrayAccess1(0, 1); + test.testArrayAccess2(0); + test.testArrayAccess3(0, false); test.testArrayAllocation(0, 1); } catch (Exception e) { // Ignore exceptions } } - public void testArrayAccess(int index, int inc) { + public void testArrayAccess1(int index, int inc) { int storeIndex = -1; for (; index < 10; index += inc) { @@ -57,7 +65,7 @@ if (index == 42) { // This store and the corresponding range check are moved out of the - // loop and both used after old loop and the peeled iteration exit. + // loop and both used after main loop and the peeled iteration exit. // For the peeled iteration, storeIndex is always -1 and the ConvI2L // is replaced by TOP. However, the range check is not folded because // we don't do the split if optimization in PhaseIdealLoop2. @@ -71,6 +79,44 @@ } } + public int testArrayAccess2(int index) { + // Load1 and the corresponding range check are moved out of the loop + // and both are used after the main loop and the peeled iteration exit. + // For the peeled iteration, storeIndex is always Integer.MIN_VALUE and + // for the main loop it is 0. Hence, the merging phi has type int:<=0. + // Load1 reads the array at index ConvI2L(CastII(AddI(storeIndex, -1))) + // where the CastII is range check dependent and has type int:>=0. + // The CastII gets pushed through the AddI and its type is changed to int:>=1 + // which does not overlap with the input type of storeIndex (int:<=0). + // The CastII is replaced by TOP causing a cascade of other eliminations. + // Since the control path through the range check CmpU(AddI(storeIndex, -1)) + // is not eliminated, the graph is in a corrupted state. We fail once we merge + // with the result of Load2 because we get data from a non-dominating region. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + + public int testArrayAccess3(int index, boolean b) { + // Same as testArrayAccess2 but manifests as crash in register allocator. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (b) { + return 0; + } + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + public byte[] testArrayAllocation(int index, int inc) { int allocationCount = -1; byte[] result; @@ -82,7 +128,7 @@ if (index == 42) { // This allocation and the corresponding size check are moved out of the - // loop and both used after old loop and the peeled iteration exit. + // loop and both used after main loop and the peeled iteration exit. // For the peeled iteration, allocationCount is always -1 and the ConvI2L // is replaced by TOP. However, the size check is not folded because // we don't do the split if optimization in PhaseIdealLoop2.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/profiling/UnsafeAccess.java Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,88 @@ +/* + * 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 8134918 + * @modules java.base/jdk.internal.misc + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -Xbatch + * -XX:CompileCommand=dontinline,UnsafeAccess::test* + * UnsafeAccess + */ +import sun.misc.Unsafe; + +public class UnsafeAccess { + private static final Unsafe U = Unsafe.getUnsafe(); + + static Class cls = Object.class; + static long off = U.ARRAY_OBJECT_BASE_OFFSET; + + static Object testUnsafeAccess(Object o, boolean isObjArray) { + if (o != null && cls.isInstance(o)) { // speculates "o" type to int[] + return helperUnsafeAccess(o, isObjArray); + } + return null; + } + + static Object helperUnsafeAccess(Object o, boolean isObjArray) { + if (isObjArray) { + U.putObject(o, off, new Object()); + } + return o; + } + + static Object testUnsafeLoadStore(Object o, boolean isObjArray) { + if (o != null && cls.isInstance(o)) { // speculates "o" type to int[] + return helperUnsafeLoadStore(o, isObjArray); + } + return null; + } + + static Object helperUnsafeLoadStore(Object o, boolean isObjArray) { + if (isObjArray) { + Object o1 = U.getObject(o, off); + U.compareAndSwapObject(o, off, o1, new Object()); + } + return o; + } + + public static void main(String[] args) { + Object[] objArray = new Object[10]; + int[] intArray = new int[10]; + + for (int i = 0; i < 20_000; i++) { + helperUnsafeAccess(objArray, true); + } + for (int i = 0; i < 20_000; i++) { + testUnsafeAccess(intArray, false); + } + + for (int i = 0; i < 20_000; i++) { + helperUnsafeLoadStore(objArray, true); + } + for (int i = 0; i < 20_000; i++) { + testUnsafeLoadStore(intArray, false); + } + + System.out.println("TEST PASSED"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/unsafe/OpaqueAccesses.java Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,181 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 8155781 + * @modules java.base/jdk.internal.misc + * + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:+UseCompressedOops -XX:+UseCompressedClassPointers + * -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test* + * compiler.unsafe.OpaqueAccesses + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:+UseCompressedOops -XX:-UseCompressedClassPointers + * -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test* + * compiler.unsafe.OpaqueAccesses + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:-UseCompressedOops -XX:+UseCompressedClassPointers + * -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test* + * compiler.unsafe.OpaqueAccesses + * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation -Xbatch + * -XX:-UseCompressedOops -XX:-UseCompressedClassPointers + * -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test* + * compiler.unsafe.OpaqueAccesses + */ +package compiler.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class OpaqueAccesses { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + private static final Object INSTANCE = new OpaqueAccesses(); + + private static final Object[] ARRAY = new Object[10]; + + private static final long F_OFFSET; + private static final long E_OFFSET; + + static { + try { + Field field = OpaqueAccesses.class.getDeclaredField("f"); + F_OFFSET = UNSAFE.objectFieldOffset(field); + + E_OFFSET = UNSAFE.arrayBaseOffset(ARRAY.getClass()); + } catch (NoSuchFieldException e) { + throw new Error(e); + } + } + + private Object f = new Object(); + private long l1, l2; + + static Object testFixedOffsetField(Object o) { + return UNSAFE.getObject(o, F_OFFSET); + } + + static int testFixedOffsetHeader0(Object o) { + return UNSAFE.getInt(o, 0); + } + + static int testFixedOffsetHeader4(Object o) { + return UNSAFE.getInt(o, 4); + } + + static int testFixedOffsetHeader8(Object o) { + return UNSAFE.getInt(o, 8); + } + + static int testFixedOffsetHeader12(Object o) { + return UNSAFE.getInt(o, 12); + } + + static int testFixedOffsetHeader16(Object o) { + return UNSAFE.getInt(o, 16); + } + + static Object testFixedBase(long off) { + return UNSAFE.getObject(INSTANCE, off); + } + + static Object testOpaque(Object o, long off) { + return UNSAFE.getObject(o, off); + } + + static int testFixedOffsetHeaderArray0(Object[] arr) { + return UNSAFE.getInt(arr, 0); + } + + static int testFixedOffsetHeaderArray4(Object[] arr) { + return UNSAFE.getInt(arr, 4); + } + + static int testFixedOffsetHeaderArray8(Object[] arr) { + return UNSAFE.getInt(arr, 8); + } + + static int testFixedOffsetHeaderArray12(Object[] arr) { + return UNSAFE.getInt(arr, 12); + } + + static int testFixedOffsetHeaderArray16(Object[] arr) { + return UNSAFE.getInt(arr, 16); + } + + static Object testFixedOffsetArray(Object[] arr) { + return UNSAFE.getObject(arr, E_OFFSET); + } + + static Object testFixedBaseArray(long off) { + return UNSAFE.getObject(ARRAY, off); + } + + static Object testOpaqueArray(Object[] o, long off) { + return UNSAFE.getObject(o, off); + } + + static final long ADDR = UNSAFE.allocateMemory(10); + static boolean flag; + + static int testMixedAccess() { + flag = !flag; + Object o = (flag ? INSTANCE : null); + long off = (flag ? F_OFFSET : ADDR); + return UNSAFE.getInt(o, off); + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + // Instance + testFixedOffsetField(INSTANCE); + testFixedOffsetHeader0(INSTANCE); + testFixedOffsetHeader4(INSTANCE); + testFixedOffsetHeader8(INSTANCE); + testFixedOffsetHeader12(INSTANCE); + testFixedOffsetHeader16(INSTANCE); + testFixedBase(F_OFFSET); + testOpaque(INSTANCE, F_OFFSET); + testMixedAccess(); + + // Array + testFixedOffsetHeaderArray0(ARRAY); + testFixedOffsetHeaderArray4(ARRAY); + testFixedOffsetHeaderArray8(ARRAY); + testFixedOffsetHeaderArray12(ARRAY); + testFixedOffsetHeaderArray16(ARRAY); + testFixedOffsetArray(ARRAY); + testFixedBaseArray(E_OFFSET); + testOpaqueArray(ARRAY, E_OFFSET); + } + System.out.println("TEST PASSED"); + } +}
--- a/test/gc/TestSoftReferencesBehaviorOnOOME.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/gc/TestSoftReferencesBehaviorOnOOME.java Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/Final/Bad.jasm Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/* Recoded in jasm to provoke an ICCE assigning a non-static final field with putstatic. +class Bad { + public static final int i; //rewritten + //rewritten to: public final int i; + static { i = 5; } // putstatic instruction +} +*/ + +super class Bad + version 52:0 +{ + +// Remove 'static' keyword +public final Field i:I; + +Method "<init>":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."<init>":"()V"; + return; +} + +static Method "<clinit>":"()V" + stack 1 locals 0 +{ + iconst_5; + putstatic Field i:"I"; + return; +} + +} // end Class Bad
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/Final/PutfieldError.java Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,42 @@ +/* + * 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 PutfieldError + * @bug 8160551 + * @summary Throw ICCE rather than crashing for nonstatic final field in static initializer + * @compile Bad.jasm + * @run main PutfieldError + */ + +public class PutfieldError { + public static void main(java.lang.String[] unused) { + try { + Bad b = new Bad(); + System.out.println("Bad.i = " + 5); + throw new RuntimeException("ICCE NOT thrown as expected"); + } catch (IncompatibleClassChangeError icce) { + System.out.println("ICCE thrown as expected"); + } + } +}
--- a/test/runtime/lambda-features/TestInterfaceInit.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/runtime/lambda-features/TestInterfaceInit.java Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,7 +25,8 @@ /* * @test * @bug 8034275 - * @summary [JDK 8u40] Test interface initialization: only for interfaces declaring default methods + * @bug 8163969 + * @summary [JDK 8u40] Test interface init: only for interfaces declaring default methods, when subclass inits * @run main TestInterfaceInit */ import java.util.List; @@ -39,43 +40,59 @@ // Declares a default method and initializes interface I { boolean v = TestInterfaceInit.out(I.class); - default void x() {} + default void ix() {} } // Declares a default method and initializes interface J extends I { boolean v = TestInterfaceInit.out(J.class); - default void x() {} + default void jx() {} } - // No default method, does not initialize + // No default method, has an abstract method, does not initialize interface JN extends J { boolean v = TestInterfaceInit.out(JN.class); + public abstract void jnx(); } // Declares a default method and initializes interface K extends I { boolean v = TestInterfaceInit.out(K.class); - default void x() {} + default void kx() {} } - // No default method, does not initialize + // No default method, has a static method, does not initialize interface KN extends K { boolean v = TestInterfaceInit.out(KN.class); + static void knx() {} } interface L extends JN, KN { boolean v = TestInterfaceInit.out(L.class); - default void x() {} + default void lx() {} + } + + static class ChildClass implements JN, KN { + boolean v = TestInterfaceInit.out(ChildClass.class); + public void jnx() {} } public static void main(String[] args) { // Trigger initialization boolean v = L.v; - List<Class<?>> expectedCInitOrder = Arrays.asList(I.class,J.class,K.class,L.class); + List<Class<?>> expectedCInitOrder = Arrays.asList(L.class); if (!cInitOrder.equals(expectedCInitOrder)) { throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder)); } + + ChildClass myC = new ChildClass(); + boolean w = myC.v; + + expectedCInitOrder = Arrays.asList(L.class,I.class,J.class,K.class,ChildClass.class); + if (!cInitOrder.equals(expectedCInitOrder)) { + throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder)); + } + } static boolean out(Class c) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/lambda-features/TestStaticandInstance.java Thu Dec 07 02:46:58 2017 +0000 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2015, 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. + * + */ + +/* + * @test + * @bug 8087342 + * @summary Test linkresolver search static, instance and overpass duplicates + * @run main/othervm -Xverify:none TestStaticandInstance + */ + + +import java.util.*; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class TestStaticandInstance { + static final String stringC = "C"; + static final String stringD = "D"; + static final String stringI = "I"; + + public static void main(String args[]) throws Throwable { + ClassLoader cl = new ClassLoader() { + public Class<?> loadClass(String name) throws ClassNotFoundException { + Class retClass; + if ((retClass = findLoadedClass(name)) != null) { + return retClass; + } + if (stringC.equals(name)) { + byte[] classFile=dumpC(); + return defineClass(stringC, classFile, 0, classFile.length); + } + if (stringD.equals(name)) { + byte[] classFile=dumpD(); + return defineClass(stringD, classFile, 0, classFile.length); + } + if (stringI.equals(name)) { + byte[] classFile=dumpI(); + return defineClass(stringI, classFile, 0, classFile.length); + } + return super.loadClass(name); + } + }; + + Class classC = cl.loadClass(stringC); + Class classI = cl.loadClass(stringI); + + try { + int staticret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallStatic").invoke(null); + if (staticret != 1) { + throw new RuntimeException("invokestatic failed to call correct method"); + } + System.out.println("staticret: " + staticret); // should be 1 + + int invokeinterfaceret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallInterface").invoke(null); + if (invokeinterfaceret != 0) { + throw new RuntimeException(String.format("Expected java.lang.AbstractMethodError, got %d", invokeinterfaceret)); + } + System.out.println("invokeinterfaceret: AbstractMethodError"); + + int invokevirtualret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallVirtual").invoke(null); + if (invokevirtualret != 0) { + throw new RuntimeException(String.format("Expected java.lang.IncompatibleClassChangeError, got %d", invokevirtualret)); + } + System.out.println("invokevirtualret: IncompatibleClassChangeError"); + } catch (java.lang.Throwable e) { + throw new RuntimeException("Unexpected exception: " + e.getMessage()); + } + } + +/* +interface I { + public int m(); // abstract + default int q() { return 3; } // trigger defmeth processing: C gets AME overpass +} + +// C gets static, private and AME overpass m()I with -Xverify:none +class C implements I { + static int m() { return 1;} // javac with "n()" and patch to "m()" + private int m() { return 2;} // javac with public and patch to private +} + +public class D { + public static int CallStatic() { + int staticret = C.m(); // javac with "C.n" and patch to "C.m" + return staticret; + } + public static int CallInterface() throws AbstractMethodError{ + try { + I myI = new C(); + return myI.m(); + } catch (java.lang.AbstractMethodError e) { + return 0; // for success + } + } + public static int CallVirtual() { + try { + C myC = new C(); + return myC.m(); + } catch (java.lang.IncompatibleClassChangeError e) { + return 0; // for success + } + } +} +*/ + + public static byte[] dumpC() { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_SUPER, "C", null, "java/lang/Object", new String[] { "I" }); + + { + mv = cw.visitMethod(0, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "m", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_1); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 0); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE, "m", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_2); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + public static byte[] dumpD () { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_PUBLIC + ACC_SUPER, "D", null, "java/lang/Object", null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallStatic", "()I", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "C", "m", "()I", false); + mv.visitVarInsn(ISTORE, 0); + mv.visitVarInsn(ILOAD, 0); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallInterface", "()I", null, new String[] { "java/lang/AbstractMethodError" }); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/AbstractMethodError"); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "C"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEINTERFACE, "I", "m", "()I", true); + mv.visitLabel(l1); + mv.visitInsn(IRETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AbstractMethodError"}); + mv.visitVarInsn(ASTORE, 0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallVirtual", "()I", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/IncompatibleClassChangeError"); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "C"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", "()I", false); + mv.visitLabel(l1); + mv.visitInsn(IRETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/IncompatibleClassChangeError"}); + mv.visitVarInsn(ASTORE, 0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + public static byte[] dumpI() { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_ABSTRACT + ACC_INTERFACE, "I", null, "java/lang/Object", null); + + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "q", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_3); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } +}
--- a/test/testlibrary/com/oracle/java/testlibrary/Utils.java Thu Nov 02 06:16:13 2017 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/Utils.java Thu Dec 07 02:46:58 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,8 +260,8 @@ output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); output.shouldHaveExitValue(0); - // Search for a line starting with numbers (pid), follwed by the key. - Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); + // Search for a line starting with numbers (pid), followed by the key. + Pattern pattern = Pattern.compile("^([0-9]+)\\s.*(" + key + ")", Pattern.MULTILINE); Matcher matcher = pattern.matcher(output.getStdout()); int pid = -1;