# HG changeset patch # User prr # Date 1504631384 25200 # Node ID 5b4ba31ce49bfcd65b01f41a3acfc82961b3ae83 # Parent 898607275d6eaa7039f5f6338df5c78025c5242a# Parent 46ab150d59cd4780b935efe74c4ea0ec06df4e56 Merge diff -r 898607275d6e -r 5b4ba31ce49b .hgtags --- a/.hgtags Sun Sep 03 19:31:11 2017 +0530 +++ b/.hgtags Tue Sep 05 10:09:44 2017 -0700 @@ -445,3 +445,4 @@ 3739654290616e533fc6f51bf9ad69ed47a6abba jdk-10+18 14df107500cc3b8ab238c3e4ad2c74e12bfe6067 jdk-10+19 4586bc5d28d13d3147b993e6237eaf29a7073bbb jdk-10+20 +a85884d55ce32799f5c7382b7ea4839052b362a2 jdk-10+21 diff -r 898607275d6e -r 5b4ba31ce49b .hgtags-top-repo --- a/.hgtags-top-repo Sun Sep 03 19:31:11 2017 +0530 +++ b/.hgtags-top-repo Tue Sep 05 10:09:44 2017 -0700 @@ -445,3 +445,4 @@ d2982a786f53814367698e63efe6349c9128e1db jdk-9+180 b656dea9398ef601f7fc08d1a5157a560e0ccbe0 jdk-9+181 682e2a6df836f4731f92eb2ddcd467075047f6ea jdk-10+20 +90cdfe56f1543267a8005e638bd1b44551fda189 jdk-10+21 diff -r 898607275d6e -r 5b4ba31ce49b common/autoconf/flags.m4 --- a/common/autoconf/flags.m4 Sun Sep 03 19:31:11 2017 +0530 +++ b/common/autoconf/flags.m4 Tue Sep 05 10:09:44 2017 -0700 @@ -1046,7 +1046,7 @@ # Set some additional per-CPU defines. if test "x$OPENJDK_$1_OS-$OPENJDK_$1_CPU" = xwindows-x86; then $2JVM_CFLAGS="[$]$2JVM_CFLAGS -arch:IA32" - elif test "x$OPENJDK_$1_CPU" = xsparcv9; then + elif test "x$OPENJDK_$1_OS-$OPENJDK_$1_CPU" = xsolaris-sparcv9; then $2JVM_CFLAGS="[$]$2JVM_CFLAGS -xarch=sparc" elif test "x$OPENJDK_$1_CPU" = xppc64; then if test "x$OPENJDK_$1_OS" = xlinux; then @@ -1358,7 +1358,7 @@ $2SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" fi $2JVM_LIBS="[$]$2JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ - -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + -lthread -ldoor -lc -ldemangle -lnsl -lrt" elif test "x$OPENJDK_$1_OS" = xmacosx; then $2JVM_LIBS="[$]$2JVM_LIBS -lm" elif test "x$OPENJDK_$1_OS" = xaix; then diff -r 898607275d6e -r 5b4ba31ce49b common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Sun Sep 03 19:31:11 2017 +0530 +++ b/common/autoconf/generated-configure.sh Tue Sep 05 10:09:44 2017 -0700 @@ -5151,7 +5151,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1503411624 +DATE_WHEN_GENERATED=1504187184 ############################################################################### # @@ -15719,6 +15719,12 @@ VAR_CPU_BITS=32 VAR_CPU_ENDIAN=little ;; + alpha*) + VAR_CPU=alpha + VAR_CPU_ARCH=alpha + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; arm*) VAR_CPU=arm VAR_CPU_ARCH=arm @@ -15731,6 +15737,36 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little ;; + m68k) + VAR_CPU=m68k + VAR_CPU_ARCH=m68k + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mips) + VAR_CPU=mips + VAR_CPU_ARCH=mips + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mipsel) + VAR_CPU=mipsel + VAR_CPU_ARCH=mipsel + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; + mips64) + VAR_CPU=mips64 + VAR_CPU_ARCH=mips64 + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=big + ;; + mips64el) + VAR_CPU=mips64el + VAR_CPU_ARCH=mips64el + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; powerpc) VAR_CPU=ppc VAR_CPU_ARCH=ppc @@ -15761,6 +15797,18 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + sh*eb) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + sh*) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; sparc) VAR_CPU=sparc VAR_CPU_ARCH=sparc @@ -15858,6 +15906,12 @@ VAR_CPU_BITS=32 VAR_CPU_ENDIAN=little ;; + alpha*) + VAR_CPU=alpha + VAR_CPU_ARCH=alpha + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; arm*) VAR_CPU=arm VAR_CPU_ARCH=arm @@ -15870,6 +15924,36 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little ;; + m68k) + VAR_CPU=m68k + VAR_CPU_ARCH=m68k + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mips) + VAR_CPU=mips + VAR_CPU_ARCH=mips + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mipsel) + VAR_CPU=mipsel + VAR_CPU_ARCH=mipsel + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; + mips64) + VAR_CPU=mips64 + VAR_CPU_ARCH=mips64 + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=big + ;; + mips64el) + VAR_CPU=mips64el + VAR_CPU_ARCH=mips64el + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; powerpc) VAR_CPU=ppc VAR_CPU_ARCH=ppc @@ -15900,6 +15984,18 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + sh*eb) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + sh*) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; sparc) VAR_CPU=sparc VAR_CPU_ARCH=sparc @@ -16045,6 +16141,12 @@ elif test "x$OPENJDK_TARGET_OS" != xmacosx && test "x$OPENJDK_TARGET_CPU" = xx86_64; then # On all platforms except MacOSX replace x86_64 with amd64. OPENJDK_TARGET_CPU_LEGACY="amd64" + elif test "x$OPENJDK_TARGET_CPU" = xalpha; then + # Avoid name collisions with variables named alpha + OPENJDK_TARGET_CPU_LEGACY="_alpha_" + elif test "x$OPENJDK_TARGET_CPU" = xsh; then + # Avoid name collisions with variables named sh + OPENJDK_TARGET_CPU_LEGACY="_sh_" fi @@ -16197,6 +16299,12 @@ elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then # On all platforms except MacOSX replace x86_64 with amd64. OPENJDK_BUILD_CPU_LEGACY="amd64" + elif test "x$OPENJDK_BUILD_CPU" = xalpha; then + # Avoid name collisions with variables named alpha + OPENJDK_BUILD_CPU_LEGACY="_alpha_" + elif test "x$OPENJDK_BUILD_CPU" = xsh; then + # Avoid name collisions with variables named sh + OPENJDK_BUILD_CPU_LEGACY="_sh_" fi @@ -51563,7 +51671,7 @@ # Set some additional per-CPU defines. if test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = xwindows-x86; then JVM_CFLAGS="$JVM_CFLAGS -arch:IA32" - elif test "x$OPENJDK_TARGET_CPU" = xsparcv9; then + elif test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = xsolaris-sparcv9; then JVM_CFLAGS="$JVM_CFLAGS -xarch=sparc" elif test "x$OPENJDK_TARGET_CPU" = xppc64; then if test "x$OPENJDK_TARGET_OS" = xlinux; then @@ -51968,7 +52076,7 @@ SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" fi JVM_LIBS="$JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ - -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + -lthread -ldoor -lc -ldemangle -lnsl -lrt" elif test "x$OPENJDK_TARGET_OS" = xmacosx; then JVM_LIBS="$JVM_LIBS -lm" elif test "x$OPENJDK_TARGET_OS" = xaix; then @@ -52442,7 +52550,7 @@ # Set some additional per-CPU defines. if test "x$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" = xwindows-x86; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -arch:IA32" - elif test "x$OPENJDK_BUILD_CPU" = xsparcv9; then + elif test "x$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" = xsolaris-sparcv9; then OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -xarch=sparc" elif test "x$OPENJDK_BUILD_CPU" = xppc64; then if test "x$OPENJDK_BUILD_OS" = xlinux; then @@ -52847,7 +52955,7 @@ OPENJDK_BUILD_SOLARIS_LIBM_LIBS="/usr/lib/sparcv9/libm.so.1" fi OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lsocket -lsched -ldl $SOLARIS_LIBM_LIBS -lCrun \ - -lthread -ldoor -lc -ldemangle -lnsl -lkstat -lrt" + -lthread -ldoor -lc -ldemangle -lnsl -lrt" elif test "x$OPENJDK_BUILD_OS" = xmacosx; then OPENJDK_BUILD_JVM_LIBS="$OPENJDK_BUILD_JVM_LIBS -lm" elif test "x$OPENJDK_BUILD_OS" = xaix; then diff -r 898607275d6e -r 5b4ba31ce49b common/autoconf/platform.m4 --- a/common/autoconf/platform.m4 Sun Sep 03 19:31:11 2017 +0530 +++ b/common/autoconf/platform.m4 Tue Sep 05 10:09:44 2017 -0700 @@ -42,6 +42,12 @@ VAR_CPU_BITS=32 VAR_CPU_ENDIAN=little ;; + alpha*) + VAR_CPU=alpha + VAR_CPU_ARCH=alpha + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; arm*) VAR_CPU=arm VAR_CPU_ARCH=arm @@ -54,6 +60,36 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little ;; + m68k) + VAR_CPU=m68k + VAR_CPU_ARCH=m68k + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mips) + VAR_CPU=mips + VAR_CPU_ARCH=mips + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + mipsel) + VAR_CPU=mipsel + VAR_CPU_ARCH=mipsel + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; + mips64) + VAR_CPU=mips64 + VAR_CPU_ARCH=mips64 + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=big + ;; + mips64el) + VAR_CPU=mips64el + VAR_CPU_ARCH=mips64el + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; powerpc) VAR_CPU=ppc VAR_CPU_ARCH=ppc @@ -84,6 +120,18 @@ VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + sh*eb) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=big + ;; + sh*) + VAR_CPU=sh + VAR_CPU_ARCH=sh + VAR_CPU_BITS=32 + VAR_CPU_ENDIAN=little + ;; sparc) VAR_CPU=sparc VAR_CPU_ARCH=sparc @@ -289,6 +337,12 @@ elif test "x$OPENJDK_$1_OS" != xmacosx && test "x$OPENJDK_$1_CPU" = xx86_64; then # On all platforms except MacOSX replace x86_64 with amd64. OPENJDK_$1_CPU_LEGACY="amd64" + elif test "x$OPENJDK_$1_CPU" = xalpha; then + # Avoid name collisions with variables named alpha + OPENJDK_$1_CPU_LEGACY="_alpha_" + elif test "x$OPENJDK_$1_CPU" = xsh; then + # Avoid name collisions with variables named sh + OPENJDK_$1_CPU_LEGACY="_sh_" fi AC_SUBST(OPENJDK_$1_CPU_LEGACY) diff -r 898607275d6e -r 5b4ba31ce49b common/conf/jib-profiles.js --- a/common/conf/jib-profiles.js Sun Sep 03 19:31:11 2017 +0530 +++ b/common/conf/jib-profiles.js Tue Sep 05 10:09:44 2017 -0700 @@ -200,7 +200,7 @@ data.configuration_make_arg = "CONF_NAME="; // Exclude list to use when Jib creates a source bundle - data.src_bundle_excludes = "./build webrev .hg */.hg */*/.hg */*/*/.hg"; + data.src_bundle_excludes = "./build webrev* */webrev* */*/webrev* */*/*/webrev* .hg */.hg */*/.hg */*/*/.hg"; // Include list to use when creating a minimal jib source bundle which // contains just the jib configuration files. data.conf_bundle_includes = "*/conf/jib-profiles.* common/autoconf/version-numbers" diff -r 898607275d6e -r 5b4ba31ce49b corba/.hgtags --- a/corba/.hgtags Sun Sep 03 19:31:11 2017 +0530 +++ b/corba/.hgtags Tue Sep 05 10:09:44 2017 -0700 @@ -445,3 +445,4 @@ 6ce6cb8ff41c71c49f23b15e0f0468aca5d52b17 jdk-9+180 ba71941ad9dba53b8fffb30602ef673eee88696c jdk-9+181 7a54ec280513a33e49e60546c0cf9ca573925a43 jdk-10+20 +68b5f8eeac3325c02aac2f4b452b8a37c20c970e jdk-10+21 diff -r 898607275d6e -r 5b4ba31ce49b hotspot/.hgtags --- a/hotspot/.hgtags Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/.hgtags Tue Sep 05 10:09:44 2017 -0700 @@ -605,3 +605,4 @@ d7baadc223e790c08bc69bf7e553bce65b4e7e40 jdk-9+180 4a443796f6f57842d6a0434ac27ca3d1033ccc20 jdk-9+181 e93ed1a092409351c90b3a76d80b9aa8b44d5e6a jdk-10+20 +bdb2dbc43ff065b74c2121bdfb0d6e1fa8684b73 jdk-10+21 diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Tue Sep 05 10:09:44 2017 -0700 @@ -3806,15 +3806,24 @@ // Any use that can't embed the address computation? for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { Node* u = addp->fast_out(i); - if (!u->is_Mem() || u->is_LoadVector() || u->is_StoreVector() || u->Opcode() == Op_StoreCM) { + if (!u->is_Mem()) { + return; + } + if (u->is_LoadVector() || u->is_StoreVector() || u->Opcode() == Op_StoreCM) { return; } + if (addp2->in(AddPNode::Offset)->Opcode() != Op_ConvI2L) { + int scale = 1 << addp2->in(AddPNode::Offset)->in(2)->get_int(); + if (VM_Version::expensive_load(u->as_Mem()->memory_size(), scale)) { + return; + } + } } - + Node* off = addp->in(AddPNode::Offset); Node* addr2 = addp2->in(AddPNode::Address); Node* base = addp->in(AddPNode::Base); - + Node* new_addr = NULL; // Check whether the graph already has the new AddP we need // before we create one (no GVN available here). @@ -3828,7 +3837,7 @@ break; } } - + if (new_addr == NULL) { new_addr = new AddPNode(base, addr2, off); } @@ -4415,6 +4424,22 @@ /*weak*/ false, noreg); %} + enc_class aarch64_enc_cmpxchgs(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + MacroAssembler _masm(&cbuf); + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, + Assembler::halfword, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + %} + + enc_class aarch64_enc_cmpxchgb(memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + MacroAssembler _masm(&cbuf); + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register, + Assembler::byte, /*acquire*/ false, /*release*/ true, + /*weak*/ false, noreg); + %} + // The only difference between aarch64_enc_cmpxchg and // aarch64_enc_cmpxchg_acq is that we use load-acquire in the @@ -9637,6 +9662,42 @@ // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher // can't match them +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ + + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgb $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgb(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ + + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgs $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgs(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); @@ -12597,6 +12658,64 @@ ins_pipe(ialu_reg_shift); %} +// We can use ubfiz when masking by a positive number and then left shifting the result. +// We know that the mask is positive because immI_bitmask guarantees it. +instruct ubfizwI(iRegINoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) +%{ + match(Set dst (LShiftI (AndI src mask) lshift)); + predicate((unsigned int)n->in(2)->get_int() <= 31 && + (exact_log2(n->in(1)->in(2)->get_int()+1) + (unsigned int)n->in(2)->get_int()) <= (31+1)); + + ins_cost(INSN_COST); + format %{ "ubfizw $dst, $src, $lshift, $mask" %} + ins_encode %{ + int lshift = $lshift$$constant; + long mask = $mask$$constant; + int width = exact_log2(mask+1); + __ ubfizw(as_Register($dst$$reg), + as_Register($src$$reg), lshift, width); + %} + ins_pipe(ialu_reg_shift); +%} +// We can use ubfiz when masking by a positive number and then left shifting the result. +// We know that the mask is positive because immL_bitmask guarantees it. +instruct ubfizL(iRegLNoSp dst, iRegL src, immI lshift, immL_bitmask mask) +%{ + match(Set dst (LShiftL (AndL src mask) lshift)); + predicate((unsigned int)n->in(2)->get_int() <= 63 && + (exact_log2_long(n->in(1)->in(2)->get_long()+1) + (unsigned int)n->in(2)->get_int()) <= (63+1)); + + ins_cost(INSN_COST); + format %{ "ubfiz $dst, $src, $lshift, $mask" %} + ins_encode %{ + int lshift = $lshift$$constant; + long mask = $mask$$constant; + int width = exact_log2(mask+1); + __ ubfiz(as_Register($dst$$reg), + as_Register($src$$reg), lshift, width); + %} + ins_pipe(ialu_reg_shift); +%} + +// If there is a convert I to L block between and AndI and a LShiftL, we can also match ubfiz +instruct ubfizIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) +%{ + match(Set dst (LShiftL (ConvI2L(AndI src mask)) lshift)); + predicate((unsigned int)n->in(2)->get_int() <= 31 && + (exact_log2((unsigned int)n->in(1)->in(1)->in(2)->get_int()+1) + (unsigned int)n->in(2)->get_int()) <= 32); + + ins_cost(INSN_COST); + format %{ "ubfiz $dst, $src, $lshift, $mask" %} + ins_encode %{ + int lshift = $lshift$$constant; + long mask = $mask$$constant; + int width = exact_log2(mask+1); + __ ubfiz(as_Register($dst$$reg), + as_Register($src$$reg), lshift, width); + %} + ins_pipe(ialu_reg_shift); +%} + // Rotations instruct extrOrL(iRegLNoSp dst, iRegL src1, iRegL src2, immI lshift, immI rshift, rFlagsReg cr) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/aarch64_ad.m4 --- a/hotspot/src/cpu/aarch64/vm/aarch64_ad.m4 Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/aarch64_ad.m4 Tue Sep 05 10:09:44 2017 -0700 @@ -214,6 +214,48 @@ ins_pipe(ialu_reg_shift); %} +define(`UBFIZ_INSN', +// We can use ubfiz when masking by a positive number and then left shifting the result. +// We know that the mask is positive because imm$1_bitmask guarantees it. +`instruct $2$1(iReg$1NoSp dst, iReg$1`'ORL2I($1) src, immI lshift, imm$1_bitmask mask) +%{ + match(Set dst (LShift$1 (And$1 src mask) lshift)); + predicate((unsigned int)n->in(2)->get_int() <= $3 && + (exact_log2$5(n->in(1)->in(2)->get_$4()+1) + (unsigned int)n->in(2)->get_int()) <= ($3+1)); + + ins_cost(INSN_COST); + format %{ "$2 $dst, $src, $lshift, $mask" %} + ins_encode %{ + int lshift = $lshift$$constant; + long mask = $mask$$constant; + int width = exact_log2(mask+1); + __ $2(as_Register($dst$$reg), + as_Register($src$$reg), lshift, width); + %} + ins_pipe(ialu_reg_shift); +%}') +UBFIZ_INSN(I, ubfizw, 31, int) +UBFIZ_INSN(L, ubfiz, 63, long, _long) + +// If there is a convert I to L block between and AndI and a LShiftL, we can also match ubfiz +instruct ubfizIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI lshift, immI_bitmask mask) +%{ + match(Set dst (LShiftL (ConvI2L(AndI src mask)) lshift)); + predicate((unsigned int)n->in(2)->get_int() <= 31 && + (exact_log2((unsigned int)n->in(1)->in(1)->in(2)->get_int()+1) + (unsigned int)n->in(2)->get_int()) <= 32); + + ins_cost(INSN_COST); + format %{ "ubfiz $dst, $src, $lshift, $mask" %} + ins_encode %{ + int lshift = $lshift$$constant; + long mask = $mask$$constant; + int width = exact_log2(mask+1); + __ ubfiz(as_Register($dst$$reg), + as_Register($src$$reg), lshift, width); + %} + ins_pipe(ialu_reg_shift); +%} + // Rotations define(`EXTRACT_INSN', diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -272,8 +272,7 @@ // load pointer for resolved_references[] objArray ldr(result, Address(result, ConstantPool::cache_offset_in_bytes())); ldr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes())); - // JNIHandles::resolve(obj); - ldr(result, Address(result, 0)); + resolve_oop_handle(result); // Add in the index add(result, result, tmp); load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -3279,6 +3279,12 @@ } } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + ldr(result, Address(result, 0)); +} + void MacroAssembler::load_mirror(Register dst, Register method) { const int mirror_offset = in_bytes(Klass::java_mirror_offset()); ldr(dst, Address(rmethod, Method::const_offset())); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -790,6 +790,7 @@ void store_klass(Register dst, Register src); void cmp_klass(Register oop, Register trial_klass, Register tmp); + void resolve_oop_handle(Register result); void load_mirror(Register dst, Register method); void load_heap_oop(Register dst, Address src); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -56,6 +56,17 @@ static void assert_is_initialized() { } + static bool expensive_load(int ld_size, int scale) { + if (cpu_family() == CPU_ARM) { + // Half-word load with index shift by 1 (aka scale is 2) has + // extra cycle latency, e.g. ldrsh w0, [x1,w2,sxtw #1]. + if (ld_size == 2 && scale == 2) { + return true; + } + } + return false; + } + enum Family { CPU_ARM = 'A', CPU_BROADCOM = 'B', diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/arm/vm/interp_masm_arm.cpp --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -300,8 +300,7 @@ // load pointer for resolved_references[] objArray ldr(cache, Address(result, ConstantPool::cache_offset_in_bytes())); ldr(cache, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes())); - // JNIHandles::resolve(result) - ldr(cache, Address(cache, 0)); + resolve_oop_handle(cache); // Add in the index // convert from field index to resolved_references() index and from // word index to byte offset. Since this is a java object, it can be compressed diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -2887,6 +2887,11 @@ return offset(); } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + ldr(result, Address(result, 0)); +} void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) { const int mirror_offset = in_bytes(Klass::java_mirror_offset()); @@ -2896,6 +2901,7 @@ ldr(mirror, Address(tmp, mirror_offset)); } + /////////////////////////////////////////////////////////////////////////////// // Compressed pointers diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -687,6 +687,7 @@ AbstractAssembler::emit_address((address)L.data()); } + void resolve_oop_handle(Register result); void load_mirror(Register mirror, Register method, Register tmp); // Porting layer between 32-bit ARM and AArch64 diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/arm/vm/methodHandles_arm.cpp --- a/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/arm/vm/methodHandles_arm.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -559,7 +559,7 @@ values.print(p); } if (Verbose) { - if (has_mh && mh->is_oop()) { + if (has_mh && oopDesc::is_oop(mh)) { mh->print(); if (java_lang_invoke_MethodHandle::is_instance(mh)) { if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -464,8 +464,7 @@ // Load pointer for resolved_references[] objArray. ld(result, ConstantPool::cache_offset_in_bytes(), result); ld(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result); - // JNIHandles::resolve(result) - ld(result, 0, result); + resolve_oop_handle(result); #ifdef ASSERT Label index_ok; lwa(R0, arrayOopDesc::length_offset_in_bytes(), result); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -3372,6 +3372,12 @@ } } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + ld(result, 0, result); +} + void MacroAssembler::load_mirror_from_const_method(Register mirror, Register const_method) { ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method); ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -725,6 +725,7 @@ void store_klass(Register dst_oop, Register klass, Register tmp = R0); void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. + void resolve_oop_handle(Register result); void load_mirror_from_const_method(Register mirror, Register const_method); static int instr_size_for_decode_klass_not_null(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -525,7 +525,7 @@ values.print(p); } - if (has_mh && mh->is_oop()) { + if (has_mh && oopDesc::is_oop(mh)) { mh->print(); if (java_lang_invoke_MethodHandle::is_instance(mh)) { if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -830,7 +830,7 @@ // Wrapper which calls oopDesc::is_oop_or_null() // Only called by MacroAssembler::verify_oop static void verify_oop_helper(const char* message, oop o) { - if (!o->is_oop_or_null()) { + if (!oopDesc::is_oop_or_null(o)) { fatal("%s", message); } ++ StubRoutines::_verify_oop_count; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -56,7 +56,7 @@ // if too small. // Run with +PrintInterpreter to get the VM to print out the size. // Max size with JVMTI -int TemplateInterpreter::InterpreterCodeSize = 230*K; +int TemplateInterpreter::InterpreterCodeSize = 256*K; #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp --- a/hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -246,8 +246,8 @@ inline void Assembler::z_mvhhi( int64_t d1, Register b1, int64_t i2) { emit_48( MVHHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } inline void Assembler::z_mvhi ( int64_t d1, Register b1, int64_t i2) { emit_48( MVHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } inline void Assembler::z_mvghi( int64_t d1, Register b1, int64_t i2) { emit_48( MVGHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } -inline void Assembler::z_mvhhi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } -inline void Assembler::z_mvhi ( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } +inline void Assembler::z_mvhhi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHHI"); z_mvhhi( d.disp(), d.baseOrR0(), i2); } +inline void Assembler::z_mvhi ( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHI"); z_mvhi( d.disp(), d.baseOrR0(), i2); } inline void Assembler::z_mvghi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVGHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } inline void Assembler::z_ex(Register r1, int64_t d2, Register x2, Register b2) { emit_32( EX_ZOPC | regz(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/compiledIC_s390.cpp --- a/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/compiledIC_s390.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -105,15 +105,18 @@ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub()); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); +#ifdef ASSERT // A generated lambda form might be deleted from the Lambdaform // cache in MethodTypeForm. If a jit compiled lambdaform method // becomes not entrant and the cache access returns null, the new // resolve will lead to a new generated LambdaForm. - - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee() || callee->is_compiled_lambda_form(), + volatile intptr_t data = method_holder->data(); + volatile address destination = jump->jump_destination(); + assert(data == 0 || data == (intptr_t)callee() || callee->is_compiled_lambda_form(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + assert(destination == (address)-1 || destination == entry, "b) MT-unsafe modification of inline cache"); +#endif // Update stub. method_holder->set_data((intptr_t)callee()); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/interp_masm_s390.cpp --- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -364,8 +364,7 @@ // Load pointer for resolved_references[] objArray. z_lg(result, ConstantPool::cache_offset_in_bytes(), result); z_lg(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result); - // JNIHandles::resolve(result) - z_lg(result, 0, result); // Load resolved references array itself. + resolve_oop_handle(result); // Load resolved references array itself. #ifdef ASSERT NearLabel index_ok; z_lgf(Z_R0, Address(result, arrayOopDesc::length_offset_in_bytes())); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -4660,6 +4660,12 @@ } } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + z_lg(result, 0, result); +} + void MacroAssembler::load_mirror(Register mirror, Register method) { mem2reg_opt(mirror, Address(method, Method::const_offset())); mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset())); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -832,6 +832,7 @@ void oop_decoder(Register Rdst, Register Rsrc, bool maybeNULL, Register Rbase = Z_R1, int pow2_offset = -1); + void resolve_oop_handle(Register result); void load_mirror(Register mirror, Register method); //-------------------------- diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/s390/vm/methodHandles_s390.cpp --- a/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/s390/vm/methodHandles_s390.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -595,7 +595,7 @@ // Note: the unextended_sp may not be correct. tty->print_cr(" stack layout:"); values.print(p); - if (has_mh && mh->is_oop()) { + if (has_mh && oopDesc::is_oop(mh)) { mh->print(); if (java_lang_invoke_MethodHandle::is_instance(mh)) { if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -730,8 +730,7 @@ // load pointer for resolved_references[] objArray ld_ptr(result, ConstantPool::cache_offset_in_bytes(), result); ld_ptr(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result); - // JNIHandles::resolve(result) - ld_ptr(result, 0, result); + resolve_oop_handle(result); // Add in the index add(result, tmp, result); load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -3822,6 +3822,12 @@ card_table_write(bs->byte_map_base, tmp, store_addr); } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + ld_ptr(result, 0, result); +} + void MacroAssembler::load_mirror(Register mirror, Register method) { const int mirror_offset = in_bytes(Klass::java_mirror_offset()); ld_ptr(method, in_bytes(Method::const_offset()), mirror); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -995,6 +995,7 @@ inline void ldbool(const Address& a, Register d); inline void movbool( bool boolconst, Register d); + void resolve_oop_handle(Register result); void load_mirror(Register mirror, Register method); // klass oop manipulations if compressed diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -562,7 +562,7 @@ // Note: the unextended_sp may not be correct tty->print_cr(" stack layout:"); values.print(p); - if (has_mh && mh->is_oop()) { + if (has_mh && oopDesc::is_oop(mh)) { mh->print(); if (java_lang_invoke_MethodHandle::is_instance(mh)) { if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/interp_masm_x86.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -511,8 +511,7 @@ // load pointer for resolved_references[] objArray movptr(result, Address(result, ConstantPool::cache_offset_in_bytes())); movptr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes())); - // JNIHandles::resolve(obj); - movptr(result, Address(result, 0)); + resolve_oop_handle(result); // Add in the index addptr(result, tmp); load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -6604,6 +6604,12 @@ #endif // _LP64 } +// ((OopHandle)result).resolve(); +void MacroAssembler::resolve_oop_handle(Register result) { + // OopHandle::resolve is an indirection. + movptr(result, Address(result, 0)); +} + void MacroAssembler::load_mirror(Register mirror, Register method) { // get mirror const int mirror_offset = in_bytes(Klass::java_mirror_offset()); @@ -7030,7 +7036,6 @@ #endif // _LP64 - // C2 compiled method's prolog code. void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -327,6 +327,7 @@ void movbool(Address dst, Register src); void testbool(Register dst); + void resolve_oop_handle(Register result); void load_mirror(Register mirror, Register method); // oop manipulations diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -561,7 +561,7 @@ tty->print_cr("Stack layout:"); values.print(p); } - if (has_mh && mh->is_oop()) { + if (has_mh && oopDesc::is_oop(mh)) { mh->print(); if (java_lang_invoke_MethodHandle::is_instance(mh)) { if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Tue Sep 05 10:09:44 2017 -0700 @@ -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 @@ -391,7 +391,7 @@ int format) { #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) { - assert(cast_to_oop(d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); + assert(oopDesc::is_oop(cast_to_oop(d32)) && (ScavengeRootsInCode || !cast_to_oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.insts_mark(), rspec, format); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2015, 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 @@ -653,7 +653,7 @@ if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) { assert(Universe::heap()->is_in_reserved((address)(intptr_t)d32), "should be real oop"); - assert(cast_to_oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !cast_to_oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); + assert(oopDesc::is_oop(cast_to_oop((intptr_t)d32)) && (ScavengeRootsInCode || !cast_to_oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.insts_mark(), rspec, format); @@ -680,7 +680,7 @@ if (rspec.reloc()->type() == relocInfo::oop_type && d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) { assert(Universe::heap()->is_in_reserved((address)d64), "should be real oop"); - assert(cast_to_oop(d64)->is_oop() && (ScavengeRootsInCode || !cast_to_oop(d64)->is_scavengable()), + assert(oopDesc::is_oop(cast_to_oop(d64)) && (ScavengeRootsInCode || !cast_to_oop(d64)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -58,7 +58,7 @@ *

* Methods to record and access code section contents, symbols and relocations are provided. */ -public class BinaryContainer implements SymbolTable { +public final class BinaryContainer implements SymbolTable { private final OptionValues graalOptions; private final int codeSegmentSize; @@ -71,19 +71,19 @@ private final CodeContainer codeContainer; /** - * Container holding external hotspot linkage bits (PLT entries). - */ - private final CodeContainer extLinkageContainer; - - /** * Container holding global offset data for hotspot linkage. */ private final ByteContainer extLinkageGOTContainer; /** - * Patched by HotSpot, contains metaspace pointers. + * Patched by HotSpot, contains Klass pointers. */ - private final ByteContainer metaspaceGotContainer; + private final ByteContainer klassesGotContainer; + + /** + * Patched by HotSpot, contains MethodCounters pointers. + */ + private final ByteContainer countersGotContainer; /** * Patched lazily by hotspot, contains klass/method pointers. @@ -268,33 +268,41 @@ this.graalOptions = graalOptions; this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize; + if (codeSegmentSize < 1 || codeSegmentSize > 1024) { + throw new InternalError("codeSegmentSize is not in range [1, 1024] bytes: (" + codeSegmentSize + "), update JPECoffRelocObject"); + } + if ((codeSegmentSize & (codeSegmentSize - 1)) != 0) { + throw new InternalError("codeSegmentSize is not power of 2: (" + codeSegmentSize + "), update JPECoffRelocObject"); + } + this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; + // Section unique name is limited to 8 characters due to limitation on Windows. + // Name could be longer but only first 8 characters are stored on Windows. + // read only, code codeContainer = new CodeContainer(".text", this); - extLinkageContainer = new CodeContainer(".hs.plt.linkage", this); // read only, info + headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this)); configContainer = new ReadOnlyDataContainer(".config", this); metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this); - methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this); + methodsOffsetsContainer = new ReadOnlyDataContainer(".meth.offsets", this); klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this); klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this); - headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this)); stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this); codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this); constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this); - - // needs relocation patching at load time by the loader methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this); // writable sections - metaspaceGotContainer = new ByteContainer(".meta.got", this); - metadataGotContainer = new ByteContainer(".metadata.got", this); + oopGotContainer = new ByteContainer(".oop.got", this); + klassesGotContainer = new ByteContainer(".kls.got", this); + countersGotContainer = new ByteContainer(".cnt.got", this); + metadataGotContainer = new ByteContainer(".meta.got", this); methodStateContainer = new ByteContainer(".meth.state", this); - oopGotContainer = new ByteContainer(".oop.got", this); - extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this); + extLinkageGOTContainer = new ByteContainer(".got.linkage", this); addGlobalSymbols(); @@ -368,51 +376,51 @@ * in the named GOT cell. */ - public String getCardTableAddressSymbolName() { + public static String getCardTableAddressSymbolName() { return "_aot_card_table_address"; } - public String getHeapTopAddressSymbolName() { + public static String getHeapTopAddressSymbolName() { return "_aot_heap_top_address"; } - public String getHeapEndAddressSymbolName() { + public static String getHeapEndAddressSymbolName() { return "_aot_heap_end_address"; } - public String getCrcTableAddressSymbolName() { + public static String getCrcTableAddressSymbolName() { return "_aot_stub_routines_crc_table_adr"; } - public String getPollingPageSymbolName() { + public static String getPollingPageSymbolName() { return "_aot_polling_page"; } - public String getResolveStaticEntrySymbolName() { + public static String getResolveStaticEntrySymbolName() { return "_resolve_static_entry"; } - public String getResolveVirtualEntrySymbolName() { + public static String getResolveVirtualEntrySymbolName() { return "_resolve_virtual_entry"; } - public String getResolveOptVirtualEntrySymbolName() { + public static String getResolveOptVirtualEntrySymbolName() { return "_resolve_opt_virtual_entry"; } - public String getNarrowKlassBaseAddressSymbolName() { + public static String getNarrowKlassBaseAddressSymbolName() { return "_aot_narrow_klass_base_address"; } - public String getNarrowOopBaseAddressSymbolName() { + public static String getNarrowOopBaseAddressSymbolName() { return "_aot_narrow_oop_base_address"; } - public String getLogOfHeapRegionGrainBytesSymbolName() { + public static String getLogOfHeapRegionGrainBytesSymbolName() { return "_aot_log_of_heap_region_grain_bytes"; } - public String getInlineContiguousAllocationSupportedSymbolName() { + public static String getInlineContiguousAllocationSupportedSymbolName() { return "_aot_inline_contiguous_allocation_supported"; } @@ -430,7 +438,7 @@ * @param functionName function name * @return AOT symbol for the given function name, or null if there is no mapping. */ - public String getAOTSymbolForVMFunctionName(String functionName) { + public static String getAOTSymbolForVMFunctionName(String functionName) { return functionNamesToAOTSymbols.get(functionName); } @@ -441,7 +449,8 @@ createContainerSymbol(methodsOffsetsContainer); createContainerSymbol(klassesOffsetsContainer); createContainerSymbol(klassesDependenciesContainer); - createContainerSymbol(metaspaceGotContainer); + createContainerSymbol(klassesGotContainer); + createContainerSymbol(countersGotContainer); createContainerSymbol(metadataGotContainer); createContainerSymbol(methodStateContainer); createContainerSymbol(oopGotContainer); @@ -469,12 +478,13 @@ } /** - * Creates a global symbol of the form {@code "JVM" + container name}. + * Creates a global symbol of the form {@code "A" + container name}. + * Note, linker on Windows does not allow names which start with '.' * * @param container container to create a symbol for */ private static void createContainerSymbol(ByteContainer container) { - container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName()); + container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "A" + container.getContainerName()); } /** @@ -499,12 +509,12 @@ * * @throws IOException in case of file creation failure */ - public void createBinary(String outputFileName, String aotVersion) throws IOException { + public void createBinary(String outputFileName) throws IOException { String osName = System.getProperty("os.name"); switch (osName) { case "Linux": case "SunOS": - JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion); + JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName); elfobj.createELFRelocObject(relocationTable, symbolTable.values()); break; case "Mac OS X": @@ -513,7 +523,7 @@ break; default: if (osName.startsWith("Windows")) { - JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion); + JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName); pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values()); break; } else @@ -626,12 +636,6 @@ return startOffset; } - public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) { - int startOffset = metaspaceGotContainer.getByteStreamSize(); - appendBytes(metaspaceGotContainer, bytes, offset, size); - return startOffset; - } - public void addMetadataGotEntry(int offset) { metadataGotContainer.appendLong(offset); } @@ -681,8 +685,7 @@ } /** - * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to - * patch. + * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch. * * @param oopName name of the oop symbol */ @@ -708,13 +711,13 @@ return relocationSymbol.getOffset(); } - public int addMetaspaceSymbol(String metaspaceName) { + public int addCountersSymbol(String metaspaceName) { String gotName = "got." + metaspaceName; Symbol relocationSymbol = getGotSymbol(gotName); int metaspaceOffset = -1; if (relocationSymbol == null) { // Add slots when asked in the .metaspace.got section: - metaspaceGotContainer.createGotSymbol(gotName); + countersGotContainer.createGotSymbol(gotName); } return metaspaceOffset; } @@ -725,29 +728,30 @@ } /** - * Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section - - * Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got - * section with another slot for the VM to patch + * Add klass symbol by as follows. + * - Adding the symbol name to the metaspace.names section + * - Add the offset of the name in metaspace.names to metaspace.offsets + * - Extend the klasses.got section with another slot for the VM to patch * - * @param metaspaceName name of the metaspace symbol - * @return the got offset in the metaspace.got of the metaspace symbol + * @param klassName name of the metaspace symbol + * @return the got offset in the klasses.got of the metaspace symbol */ - public int addTwoSlotMetaspaceSymbol(String metaspaceName) { - String gotName = "got." + metaspaceName; + public int addTwoSlotKlassSymbol(String klassName) { + String gotName = "got." + klassName; Symbol previous = getGotSymbol(gotName); - assert previous == null : "should be called only once for: " + metaspaceName; + assert previous == null : "should be called only once for: " + klassName; // Add slots when asked in the .metaspace.got section: // First slot - String gotInitName = "got.init." + metaspaceName; - GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName); - GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName); + String gotInitName = "got.init." + klassName; + GotSymbol slot1Symbol = klassesGotContainer.createGotSymbol(gotInitName); + GotSymbol slot2Symbol = klassesGotContainer.createGotSymbol(gotName); slot1Symbol.getIndex(); // check alignment and ignore result // Get the index (offset/8) to the got in the .metaspace.got section return slot2Symbol.getIndex(); } - public int addMethodsCount(int count, ReadOnlyDataContainer container) { + public static int addMethodsCount(int count, ReadOnlyDataContainer container) { return appendInt(count, container); } @@ -772,7 +776,7 @@ return constantDataOffset; } - public int alignUp(ByteContainer container, int alignment) { + public static int alignUp(ByteContainer container, int alignment) { if (Integer.bitCount(alignment) != 1) { throw new IllegalArgumentException("Must be a power of 2"); } @@ -814,15 +818,11 @@ appendBytes(codeSegmentsContainer, segments, 0, segmentsCount); } - public CodeContainer getExtLinkageContainer() { - return extLinkageContainer; - } - public ByteContainer getExtLinkageGOTContainer() { return extLinkageGOTContainer; } - public ByteContainer getMethodMetadataContainer() { + public ReadOnlyDataContainer getMethodMetadataContainer() { return methodMetadataContainer; } @@ -854,8 +854,12 @@ return constantDataContainer; } - public ByteContainer getMetaspaceGotContainer() { - return metaspaceGotContainer; + public ByteContainer getKlassesGotContainer() { + return klassesGotContainer; + } + + public ByteContainer getCountersGotContainer() { + return countersGotContainer; } public ByteContainer getMetadataGotContainer() { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/CodeContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -26,7 +26,7 @@ /** * A container that holds information about code section. This is simply a ByteContainer. */ -public class CodeContainer extends ByteContainer { +public final class CodeContainer extends ByteContainer { public CodeContainer(String containerName, SymbolTable symbolTable) { super(containerName, symbolTable); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Container.java Tue Sep 05 10:09:44 2017 -0700 @@ -23,7 +23,7 @@ package jdk.tools.jaotc.binformat; -public interface Container { +interface Container { String getContainerName(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/GotSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,7 +23,7 @@ package jdk.tools.jaotc.binformat; -public class GotSymbol extends Symbol { +public final class GotSymbol extends Symbol { private static final int GOT_SIZE = 8; @@ -33,18 +33,27 @@ return offset / GOT_SIZE; } + /** + * Create GOT symbol info. + * + * @param type type of the symbol (UNDEFINED, FUNC, etc) + * @param binding binding of the symbol (LOCAL, GLOBAL, ...) + * @param container section in which this symbol is "defined" + * @param name name of the symbol + */ public GotSymbol(Kind type, Binding binding, ByteContainer container, String name) { this(container.getByteStreamSize(), type, binding, container, name); container.appendBytes(new byte[GOT_SIZE], 0, GOT_SIZE); } /** - * Create symbol info. + * Create GOT symbol info. * * @param offset section offset for the defined symbol * @param type type of the symbol (UNDEFINED, FUNC, etc) * @param binding binding of the symbol (LOCAL, GLOBAL, ...) * @param sec section in which this symbol is "defined" + * @param name name of the symbol */ public GotSymbol(int offset, Kind type, Binding binding, ByteContainer sec, String name) { super(offset, type, binding, sec, GOT_SIZE, name); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/HeaderContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -27,14 +27,15 @@ import java.io.DataOutputStream; import java.io.IOException; -public class HeaderContainer { +public final class HeaderContainer { private static final int CURRENT_VERSION = 1; private final ReadOnlyDataContainer container; + // int _version; // int _class_count; // int _method_count; - // int _metaspace_got_size; + // int _klasses_got_size; // int _metadata_got_size; // int _oop_got_size; // int _jvm_version_offset; @@ -76,7 +77,7 @@ this.container.putIntAt(2 * 4, count); } - public void setMetaspaceGotSize(int size) { + public void setKlassesGotSize(int size) { this.container.putIntAt(3 * 4, size); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/ReadOnlyDataContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,9 +23,9 @@ package jdk.tools.jaotc.binformat; -public class ReadOnlyDataContainer extends ByteContainer { +public final class ReadOnlyDataContainer extends ByteContainer { - public ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) { + ReadOnlyDataContainer(String containerName, SymbolTable symbolTable) { super(containerName, symbolTable); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Relocation.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,25 +23,17 @@ package jdk.tools.jaotc.binformat; -public class Relocation { +public final class Relocation { public enum RelocType { UNDEFINED, JAVA_CALL_INDIRECT, JAVA_CALL_DIRECT, - FOREIGN_CALL_INDIRECT, FOREIGN_CALL_INDIRECT_GOT, // Call to address in GOT cell - FOREIGN_CALL_DIRECT, - FOREIGN_CALL_DIRECT_FAR, STUB_CALL_DIRECT, - STUB_CALL_INDIRECT, - EXTERNAL_DATA_REFERENCE_FAR, METASPACE_GOT_REFERENCE, EXTERNAL_GOT_TO_PLT, - EXTERNAL_PLT_TO_GOT, - STATIC_STUB_TO_STATIC_METHOD, - STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT, - LOADTIME_ADDRESS + EXTERNAL_PLT_TO_GOT } private final RelocType type; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/Symbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -39,7 +39,6 @@ UNDEFINED, NATIVE_FUNCTION, JAVA_FUNCTION, - STATIC_STUB_CALL, // static call stub inside the text section OBJECT, NOTYPE } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/Elf.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,17 +25,16 @@ /** * - * Support for the creation of Elf Object files. - * Current support is limited to 64 bit x86_64. + * Support for the creation of Elf Object files. Current support is limited to 64 bit x86_64. * */ -public class Elf { - +final class Elf { + //@formatter:off /** * Elf64_Ehdr structure defines */ - public enum Elf64_Ehdr { + enum Elf64_Ehdr { e_ident( 0,16), e_type(16, 2), e_machine(18, 2), @@ -51,15 +50,15 @@ e_shnum(60, 2), e_shstrndx(62, 2); - public final int off; - public final int sz; + final int off; + final int sz; Elf64_Ehdr(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 64; + static int totalsize = 64; /** * Elf64_Ehdr defines @@ -68,50 +67,44 @@ /** * e_ident */ - public static final int EI_MAG0 = 0; - public static final byte ELFMAG0 = 0x7f; - public static final int EI_MAG1 = 1; - public static final byte ELFMAG1 = 0x45; - public static final int EI_MAG2 = 2; - public static final byte ELFMAG2 = 0x4c; - public static final int EI_MAG3 = 3; - public static final byte ELFMAG3 = 0x46; + static final int EI_MAG0 = 0; + static final byte ELFMAG0 = 0x7f; + static final int EI_MAG1 = 1; + static final byte ELFMAG1 = 0x45; + static final int EI_MAG2 = 2; + static final byte ELFMAG2 = 0x4c; + static final int EI_MAG3 = 3; + static final byte ELFMAG3 = 0x46; + static final int EI_CLASS = 4; + static final byte ELFCLASS64 = 0x2; - public static final int EI_CLASS = 4; - public static final byte ELFCLASS64 = 0x2; - - public static final int EI_DATA = 5; - public static final byte ELFDATA2LSB = 0x1; + static final int EI_DATA = 5; + static final byte ELFDATA2LSB = 0x1; - public static final int EI_VERSION = 6; - public static final byte EV_CURRENT = 0x1; + static final int EI_VERSION = 6; + static final byte EV_CURRENT = 0x1; - public static final int EI_OSABI = 7; - public static final byte ELFOSABI_NONE = 0x0; + static final int EI_OSABI = 7; + static final byte ELFOSABI_NONE = 0x0; /** * e_type */ - public static final char ET_REL = 0x1; + static final char ET_REL = 0x1; /** * e_machine */ - public static final char EM_NONE = 0; - public static final char EM_X86_64 = 62; - public static final char EM_AARCH64 = 183; - - /** - * e_version - */ - // public static final int EV_CURRENT = 1; + static final char EM_NONE = 0; + static final char EM_X86_64 = 62; + static final char EM_AARCH64 = 183; } /** * Elf64_Shdr structure defines */ - public enum Elf64_Shdr { + enum Elf64_Shdr { sh_name( 0, 4), sh_type( 4, 4), sh_flags( 8, 8), @@ -123,15 +116,15 @@ sh_addralign(48, 8), sh_entsize(56, 8); - public final int off; - public final int sz; + final int off; + final int sz; Elf64_Shdr(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 64; + static int totalsize = 64; /** * Elf64_Shdr defines @@ -140,21 +133,21 @@ /** * sh_type */ - public static final int SHT_PROGBITS = 0x1; - public static final int SHT_SYMTAB = 0x2; - public static final int SHT_STRTAB = 0x3; - public static final int SHT_RELA = 0x4; - public static final int SHT_NOBITS = 0x8; - public static final int SHT_REL = 0x9; + static final int SHT_PROGBITS = 0x1; + static final int SHT_SYMTAB = 0x2; + static final int SHT_STRTAB = 0x3; + static final int SHT_RELA = 0x4; + static final int SHT_NOBITS = 0x8; + static final int SHT_REL = 0x9; - public static final byte SHN_UNDEF = 0x0; + static final byte SHN_UNDEF = 0x0; /** * sh_flag */ - public static final int SHF_WRITE = 0x1; - public static final int SHF_ALLOC = 0x2; - public static final int SHF_EXECINSTR = 0x4; + static final int SHF_WRITE = 0x1; + static final int SHF_ALLOC = 0x2; + static final int SHF_EXECINSTR = 0x4; } @@ -163,7 +156,7 @@ * * Elf64_Sym structure defines */ - public enum Elf64_Sym { + enum Elf64_Sym { st_name( 0, 4), st_info( 4, 1), st_other( 5, 1), @@ -171,25 +164,25 @@ st_value( 8, 8), st_size(16, 8); - public final int off; - public final int sz; + final int off; + final int sz; Elf64_Sym(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 24; + static int totalsize = 24; /* ST_BIND is in bits 4-7 of st_info. ST_TYPE is in low 4 bits */ - public static final byte STB_LOCAL = 0x0; - public static final byte STB_GLOBAL = 0x1; + static final byte STB_LOCAL = 0x0; + static final byte STB_GLOBAL = 0x1; - public static final byte STT_NOTYPE = 0x0; - public static final byte STT_OBJECT = 0x1; - public static final byte STT_FUNC = 0x2; + static final byte STT_NOTYPE = 0x0; + static final byte STT_OBJECT = 0x1; + static final byte STT_FUNC = 0x2; - public static byte ELF64_ST_INFO(byte bind, byte type) { + static byte ELF64_ST_INFO(byte bind, byte type) { return (byte)(((bind) << 4) + ((type) & 0xf)); } @@ -198,59 +191,59 @@ /** * Elf64_Rel structure defines */ - public enum Elf64_Rel { + enum Elf64_Rel { r_offset( 0, 8), r_info( 8, 8); - public final int off; - public final int sz; + final int off; + final int sz; Elf64_Rel(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 16; + static int totalsize = 16; /** * Relocation types */ - public static final int R_X86_64_NONE = 0x0; - public static final int R_X86_64_64 = 0x1; - public static final int R_X86_64_PC32 = 0x2; - public static final int R_X86_64_PLT32 = 0x4; - public static final int R_X86_64_GOTPCREL = 0x9; + static final int R_X86_64_NONE = 0x0; + static final int R_X86_64_64 = 0x1; + static final int R_X86_64_PC32 = 0x2; + static final int R_X86_64_PLT32 = 0x4; + static final int R_X86_64_GOTPCREL = 0x9; } /** * Elf64_Rela structure defines */ - public enum Elf64_Rela { + enum Elf64_Rela { r_offset( 0, 8), r_info( 8, 8), r_addend(16, 8); - public final int off; - public final int sz; + final int off; + final int sz; Elf64_Rela(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 24; + static int totalsize = 24; - public static final int R_X86_64_NONE = 0x0; - public static final int R_X86_64_64 = 0x1; - public static final int R_X86_64_PC32 = 0x2; - public static final int R_X86_64_PLT32 = 0x4; - public static final int R_X86_64_GOTPCREL = 0x9; + static final int R_X86_64_NONE = 0x0; + static final int R_X86_64_64 = 0x1; + static final int R_X86_64_PC32 = 0x2; + static final int R_X86_64_PLT32 = 0x4; + static final int R_X86_64_GOTPCREL = 0x9; - public static long ELF64_R_INFO(int symidx, int type) { - return (((long)symidx << 32) + ((long)type)); + static long ELF64_R_INFO(int symidx, int type) { + return (((long)symidx << 32) + type); } } - + //@formatter:on } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfByteBuffer.java Tue Sep 05 10:09:44 2017 -0700 @@ -23,20 +23,20 @@ package jdk.tools.jaotc.binformat.elf; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; -public class ElfByteBuffer { +final class ElfByteBuffer { - public static ByteBuffer allocate(int size) { + static ByteBuffer allocate(int size) { ByteBuffer buf = ByteBuffer.allocate(size); - if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB) + if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB) { buf.order(ByteOrder.LITTLE_ENDIAN); - else + } else { buf.order(ByteOrder.BIG_ENDIAN); + } return (buf); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -26,14 +26,13 @@ import java.io.File; import java.io.FileOutputStream; -public class ElfContainer { +final class ElfContainer { - File outputFile; - FileOutputStream outputStream; - long fileOffset; + private final File outputFile; + private FileOutputStream outputStream; + private long fileOffset; - public ElfContainer(String fileName, String aotVersion) { - String baseName; + ElfContainer(String fileName) { outputFile = new File(fileName); if (outputFile.exists()) { @@ -48,7 +47,7 @@ fileOffset = 0; } - public void close() { + void close() { try { outputStream.close(); } catch (Exception e) { @@ -56,8 +55,10 @@ } } - public void writeBytes(byte [] bytes) { - if (bytes == null) return; + void writeBytes(byte[] bytes) { + if (bytes == null) { + return; + } try { outputStream.write(bytes); } catch (Exception e) { @@ -67,11 +68,13 @@ } // Write bytes to output file with up front alignment padding - public void writeBytes(byte [] bytes, int alignment) { - if (bytes == null) return; + void writeBytes(byte[] bytes, int alignment) { + if (bytes == null) { + return; + } try { // Pad to alignment - while ((fileOffset & (long)(alignment-1)) != 0) { + while ((fileOffset & (alignment - 1)) != 0) { outputStream.write(0); fileOffset++; } @@ -82,4 +85,3 @@ fileOffset += bytes.length; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfHeader.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,55 +24,52 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr; import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfHeader { - ByteBuffer header; +final class ElfHeader { + private final ByteBuffer header; - public ElfHeader() { + ElfHeader() { header = ElfByteBuffer.allocate(Elf64_Ehdr.totalsize); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT); - header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT); + header.put(Elf64_Ehdr.e_ident.off + Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE); header.putChar(Elf64_Ehdr.e_type.off, Elf64_Ehdr.ET_REL); header.putChar(Elf64_Ehdr.e_machine.off, ElfTargetInfo.getElfArch()); header.putInt(Elf64_Ehdr.e_version.off, Elf64_Ehdr.EV_CURRENT); - header.putChar(Elf64_Ehdr.e_ehsize.off, (char)Elf64_Ehdr.totalsize); - header.putChar(Elf64_Ehdr.e_shentsize.off, (char)Elf64_Shdr.totalsize); + header.putChar(Elf64_Ehdr.e_ehsize.off, (char) Elf64_Ehdr.totalsize); + header.putChar(Elf64_Ehdr.e_shentsize.off, (char) Elf64_Shdr.totalsize); } // Update header with file offset of first section - public void setSectionOff(int offset) { + void setSectionOff(int offset) { header.putLong(Elf64_Ehdr.e_shoff.off, offset); } // Update header with the number of total sections - public void setSectionNum(int count) { - header.putChar(Elf64_Ehdr.e_shnum.off, (char)count); + void setSectionNum(int count) { + header.putChar(Elf64_Ehdr.e_shnum.off, (char) count); } // Update header with the section index containing the // string table for section names - public void setSectionStrNdx(int index) { - header.putChar(Elf64_Ehdr.e_shstrndx.off, (char)index); + void setSectionStrNdx(int index) { + header.putChar(Elf64_Ehdr.e_shstrndx.off, (char) index); } - public byte[] getArray() { + byte[] getArray() { return header.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocEntry.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,28 +24,23 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; -import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; -import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfRelocEntry { - ByteBuffer entry; +final class ElfRelocEntry { + private final ByteBuffer entry; - public ElfRelocEntry(int offset, int symno, int type, int addend) { + ElfRelocEntry(int offset, int symno, int type, int addend) { entry = ElfByteBuffer.allocate(Elf64_Rela.totalsize); entry.putLong(Elf64_Rela.r_offset.off, offset); - entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno,type)); + entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno, type)); entry.putLong(Elf64_Rela.r_addend.off, addend); } - public byte[] getArray() { + byte[] getArray() { return entry.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfRelocTable.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,48 +25,38 @@ import java.util.ArrayList; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.elf.ElfRelocEntry; -import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; -import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfRelocTable { - ArrayList> relocEntries; +final class ElfRelocTable { + private final ArrayList> relocEntries; - public ElfRelocTable(int numsects) { - relocEntries = new ArrayList>(numsects); - for (int i = 0; i < numsects; i++) + ElfRelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { relocEntries.add(new ArrayList()); + } } - public void createRelocationEntry(int sectindex, - int offset, - int symno, - int type, - int addend) { - - ElfRelocEntry entry = new ElfRelocEntry(offset, - symno, - type, - addend); + void createRelocationEntry(int sectindex, int offset, int symno, int type, int addend) { + ElfRelocEntry entry = new ElfRelocEntry(offset, symno, type, addend); relocEntries.get(sectindex).add(entry); } - public int getNumRelocs(int section_index) { + int getNumRelocs(int section_index) { return relocEntries.get(section_index).size(); } // Return the relocation entries for a single section - // or null if no entries added to section - public byte [] getRelocData(int section_index) { + // or null if no entries added to section + byte[] getRelocData(int section_index) { ArrayList entryList = relocEntries.get(section_index); - if (entryList.size() == 0) + if (entryList.size() == 0) { return null; - + } ByteBuffer relocData = ElfByteBuffer.allocate(entryList.size() * Elf64_Rela.totalsize); // Copy each entry to a single ByteBuffer @@ -78,4 +68,3 @@ return (relocData.array()); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSection.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,40 +24,36 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.elf.Elf; -import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfSection { - String name; - ByteBuffer section; - byte [] data; - boolean hasrelocations; - int sectionIndex; +final class ElfSection { + private final String name; + private final ByteBuffer section; + private final byte[] data; + private final boolean hasrelocations; + private final int sectionIndex; /** * String holding section name strings */ - private static StringBuilder sectNameTab = new StringBuilder(); + private final static StringBuilder sectNameTab = new StringBuilder(); /** - * Keeps track of bytes in section string table since strTabContent.length() - * is number of chars, not bytes. + * Keeps track of bytes in section string table since strTabContent.length() is number of chars, + * not bytes. */ private static int shStrTabNrOfBytes = 0; - public ElfSection(String sectName, byte [] sectData, int sectFlags, - int sectType, boolean hasRelocations, int align, - int sectIndex) { + ElfSection(String sectName, byte[] sectData, int sectFlags, int sectType, + boolean hasRelocations, int align, int sectIndex) { section = ElfByteBuffer.allocate(Elf64_Shdr.totalsize); - + name = sectName; // Return all 0's for NULL section if (sectIndex == 0) { sectNameTab.append('\0'); @@ -71,7 +67,6 @@ section.putInt(Elf64_Shdr.sh_name.off, shStrTabNrOfBytes); sectNameTab.append(sectName).append('\0'); shStrTabNrOfBytes += (sectName.getBytes().length + 1); - name = sectName; section.putInt(Elf64_Shdr.sh_type.off, sectType); section.putLong(Elf64_Shdr.sh_flags.off, sectFlags); @@ -81,8 +76,7 @@ if (sectName.equals(".shstrtab")) { section.putLong(Elf64_Shdr.sh_size.off, shStrTabNrOfBytes); data = sectNameTab.toString().getBytes(); - } - else { + } else { data = sectData; section.putLong(Elf64_Shdr.sh_size.off, sectData.length); } @@ -110,55 +104,53 @@ sectionIndex = sectIndex; } - public String getName() { + String getName() { return name; } - public long getSize() { + long getSize() { return section.getLong(Elf64_Shdr.sh_size.off); } - public int getDataAlign() { - return ((int)section.getLong(Elf64_Shdr.sh_addralign.off)); + int getDataAlign() { + return ((int) section.getLong(Elf64_Shdr.sh_addralign.off)); } // Alignment requirements for the Elf64_Shdr structures - public static int getShdrAlign() { + static int getShdrAlign() { return (4); } - public byte[] getArray() { + byte[] getArray() { return section.array(); } - public byte[] getDataArray() { + byte[] getDataArray() { return data; } - public void setOffset(long offset) { + void setOffset(long offset) { section.putLong(Elf64_Shdr.sh_offset.off, offset); } - public void setLink(int link) { + void setLink(int link) { section.putInt(Elf64_Shdr.sh_link.off, link); } - public void setInfo(int info) { + void setInfo(int info) { section.putInt(Elf64_Shdr.sh_info.off, info); } - public long getOffset() { + long getOffset() { return (section.getLong(Elf64_Shdr.sh_offset.off)); } - public boolean hasRelocations() { + boolean hasRelocations() { return hasrelocations; } - public int getSectionId() { + int getSectionId() { return sectionIndex; } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,34 +24,29 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.NativeSymbol; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; -import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfSymbol extends NativeSymbol { - ByteBuffer sym; +final class ElfSymbol extends NativeSymbol { + private final ByteBuffer sym; - public ElfSymbol(int symbolindex, int strindex, byte type, byte bind, - byte sectindex, long offset, long size) { + ElfSymbol(int symbolindex, int strindex, byte type, byte bind, byte sectindex, long offset, long size) { super(symbolindex); sym = ElfByteBuffer.allocate(Elf64_Sym.totalsize); sym.putInt(Elf64_Sym.st_name.off, strindex); sym.put(Elf64_Sym.st_info.off, Elf64_Sym.ELF64_ST_INFO(bind, type)); - sym.put(Elf64_Sym.st_other.off, (byte)0); + sym.put(Elf64_Sym.st_other.off, (byte) 0); // Section indexes start at 1 but we manage the index internally // as 0 relative - sym.putChar(Elf64_Sym.st_shndx.off, (char)(sectindex)); + sym.putChar(Elf64_Sym.st_shndx.off, (char) (sectindex)); sym.putLong(Elf64_Sym.st_value.off, offset); sym.putLong(Elf64_Sym.st_size.off, size); } - public byte[] getArray() { + byte[] getArray() { return sym.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfSymtab.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,41 +24,38 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.ArrayList; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; import jdk.tools.jaotc.binformat.elf.ElfSymbol; import jdk.tools.jaotc.binformat.elf.ElfByteBuffer; -public class ElfSymtab { +final class ElfSymtab { - ArrayListlocalSymbols = new ArrayList(); - ArrayListglobalSymbols = new ArrayList(); + private final ArrayList localSymbols = new ArrayList<>(); + private final ArrayList globalSymbols = new ArrayList<>(); /** * number of symbols added */ - int symbolCount; + private int symbolCount; /** * String holding symbol table strings */ - private StringBuilder strTabContent = new StringBuilder(); + private final StringBuilder strTabContent = new StringBuilder(); /** - * Keeps track of bytes in string table since strTabContent.length() - * is number of chars, not bytes. + * Keeps track of bytes in string table since strTabContent.length() is number of chars, not + * bytes. */ private int strTabNrOfBytes = 0; - public ElfSymtab() { + ElfSymtab() { symbolCount = 0; } - public ElfSymbol addSymbolEntry(String name, byte type, byte bind, - byte secHdrIndex, long offset, long size) { + ElfSymbol addSymbolEntry(String name, byte type, byte bind, byte secHdrIndex, long offset, long size) { // Get the current symbol index and append symbol name to string table. int index; ElfSymbol sym; @@ -76,7 +73,7 @@ // strTabContent.append("_").append(name).append('\0'); strTabContent.append(name).append('\0'); // + 1 for null, + 1 for "_" - //strTabNrOfBytes += (name.getBytes().length + 1 + 1); + // strTabNrOfBytes += (name.getBytes().length + 1 + 1); strTabNrOfBytes += (name.getBytes().length + 1); sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size); @@ -92,44 +89,47 @@ // Update the symbol indexes once all symbols have been added. // This is required since we'll be reordering the symbols in the // file to be in the order of Local then global. - public void updateIndexes() { + void updateIndexes() { int index = 0; // Update the local symbol indexes - for (int i = 0; i < localSymbols.size(); i++ ) { + for (int i = 0; i < localSymbols.size(); i++) { ElfSymbol sym = localSymbols.get(i); sym.setIndex(index++); } // Update the global symbol indexes - for (int i = 0; i < globalSymbols.size(); i++ ) { + for (int i = 0; i < globalSymbols.size(); i++) { ElfSymbol sym = globalSymbols.get(i); sym.setIndex(index++); } } - public int getNumLocalSyms() { return localSymbols.size(); } - public int getNumGlobalSyms() { return globalSymbols.size(); } + int getNumLocalSyms() { + return localSymbols.size(); + } + int getNumGlobalSyms() { + return globalSymbols.size(); + } // Create a single byte array that contains the symbol table entries - public byte[] getSymtabArray() { - int index = 0; - ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount*Elf64_Sym.totalsize); - byte [] retarray; + byte[] getSymtabArray() { + ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount * Elf64_Sym.totalsize); + byte[] retarray; updateIndexes(); // Add the local symbols - for (int i = 0; i < localSymbols.size(); i++ ) { + for (int i = 0; i < localSymbols.size(); i++) { ElfSymbol sym = localSymbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } // Add the global symbols - for (int i = 0; i < globalSymbols.size(); i++ ) { + for (int i = 0; i < globalSymbols.size(); i++) { ElfSymbol sym = globalSymbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } retarray = symtabData.array(); @@ -138,10 +138,8 @@ } // Return the string table array - public byte[] getStrtabArray() { - byte [] strs = strTabContent.toString().getBytes(); + byte[] getStrtabArray() { + byte[] strs = strTabContent.toString().getBytes(); return (strs); } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,14 +24,13 @@ package jdk.tools.jaotc.binformat.elf; import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; /** * Class that abstracts MACH-O target details. * */ -public class ElfTargetInfo { +final class ElfTargetInfo { /** * Target architecture. */ @@ -68,16 +67,15 @@ } } - public static char getElfArch() { + static char getElfArch() { return arch; } - public static int getElfEndian() { + static int getElfEndian() { return endian; } - public static String getOsName() { + static String getOsName() { return osName; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/JELFRelocObject.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,13 +24,11 @@ package jdk.tools.jaotc.binformat.elf; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import jdk.tools.jaotc.binformat.Container; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; import jdk.tools.jaotc.binformat.CodeContainer; @@ -38,17 +36,14 @@ import jdk.tools.jaotc.binformat.Relocation; import jdk.tools.jaotc.binformat.Relocation.RelocType; import jdk.tools.jaotc.binformat.Symbol; -import jdk.tools.jaotc.binformat.NativeSymbol; import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; -import jdk.tools.jaotc.binformat.elf.Elf; import jdk.tools.jaotc.binformat.elf.ElfSymbol; import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; -import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel; import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; public class JELFRelocObject { @@ -59,34 +54,29 @@ private final int segmentSize; - public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) { + public JELFRelocObject(BinaryContainer binContainer, String outputFileName) { this.binContainer = binContainer; - this.elfContainer = new ElfContainer(outputFileName, aotVersion); + this.elfContainer = new ElfContainer(outputFileName); this.segmentSize = binContainer.getCodeSegmentSize(); } - private ElfSection createByteSection(ArrayListsections, - String sectName, - byte [] scnData, - boolean hasRelocs, - int align, - int scnFlags, - int scnType) { + private static ElfSection createByteSection(ArrayList sections, + String sectName, + byte[] scnData, + boolean hasRelocs, + int align, + int scnFlags, + int scnType) { - ElfSection sect = new ElfSection(sectName, - scnData, - scnFlags, - scnType, - hasRelocs, - align, - sections.size()); + ElfSection sect = new ElfSection(sectName, scnData, scnFlags, scnType, + hasRelocs, align, sections.size()); // Add this section to our list sections.add(sect); return (sect); } - private void createByteSection(ArrayListsections, + private void createByteSection(ArrayList sections, ByteContainer c, int scnFlags) { ElfSection sect; boolean hasRelocs = c.hasRelocations(); @@ -112,15 +102,15 @@ c.setSectionId(sect.getSectionId()); } - private void createCodeSection(ArrayListsections, CodeContainer c) { + private void createCodeSection(ArrayList sections, CodeContainer c) { createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR); } - private void createReadOnlySection(ArrayListsections, ReadOnlyDataContainer c) { + private void createReadOnlySection(ArrayList sections, ReadOnlyDataContainer c) { createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC); } - private void createReadWriteSection(ArrayListsections, ByteContainer c) { + private void createReadWriteSection(ArrayList sections, ByteContainer c) { createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE); } @@ -135,7 +125,7 @@ // Allocate ELF Header ElfHeader eh = new ElfHeader(); - ArrayList sections = new ArrayList(); + ArrayList sections = new ArrayList<>(); // Create the null section createByteSection(sections, null, null, false, 1, 0, 0); @@ -146,63 +136,49 @@ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); - createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); - createReadWriteSection(sections, binContainer.getMetadataGotContainer()); - createReadWriteSection(sections, binContainer.getMethodStateContainer()); - createReadWriteSection(sections, binContainer.getOopGotContainer()); - createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); + createReadOnlySection(sections, binContainer.getMethodMetadataContainer()); createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); createReadOnlySection(sections, binContainer.getConstantDataContainer()); createReadOnlySection(sections, binContainer.getConfigContainer()); - - // createExternalLinkage(); - - createCodeSection(sections, binContainer.getExtLinkageContainer()); + createReadWriteSection(sections, binContainer.getKlassesGotContainer()); + createReadWriteSection(sections, binContainer.getCountersGotContainer()); + createReadWriteSection(sections, binContainer.getMetadataGotContainer()); + createReadWriteSection(sections, binContainer.getOopGotContainer()); + createReadWriteSection(sections, binContainer.getMethodStateContainer()); createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); // Get ELF symbol data from BinaryContainer object's symbol tables - ElfSymtab symtab = createELFSymbolTables(sections, symbols); + ElfSymtab symtab = createELFSymbolTables(symbols); // Create string table section and symbol table sections in // that order since symtab section needs to set the index of // strtab in sh_link field - ElfSection strTabSection = createByteSection(sections, - ".strtab", + ElfSection strTabSection = createByteSection(sections, ".strtab", symtab.getStrtabArray(), - false, - 1, - 0, + false, 1, 0, Elf64_Shdr.SHT_STRTAB); // Now create .symtab section with the symtab data constructed. // On Linux, sh_link of symtab contains the index of string table // its symbols reference and sh_info contains the index of first // non-local symbol - ElfSection symTabSection = createByteSection(sections, - ".symtab", - symtab.getSymtabArray(), - false, - 8, - 0, - Elf64_Shdr.SHT_SYMTAB); + ElfSection symTabSection = createByteSection(sections, ".symtab", + symtab.getSymtabArray(), + false, 8, 0, + Elf64_Shdr.SHT_SYMTAB); symTabSection.setLink(strTabSection.getSectionId()); symTabSection.setInfo(symtab.getNumLocalSyms()); - ElfRelocTable elfRelocTable = createElfRelocTable(sections, - relocationTable); + ElfRelocTable elfRelocTable = createElfRelocTable(sections, relocationTable); createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId()); // Now, finally, after creating all sections, create shstrtab section - ElfSection shStrTabSection = createByteSection(sections, - ".shstrtab", - null, - false, - 1, - 0, - Elf64_Shdr.SHT_STRTAB); + ElfSection shStrTabSection = createByteSection(sections, ".shstrtab", + null, false, 1, 0, + Elf64_Shdr.SHT_STRTAB); eh.setSectionStrNdx(shStrTabSection.getSectionId()); // Update all section offsets and the Elf header section offset @@ -211,21 +187,21 @@ int file_offset = Elf64_Ehdr.totalsize; // and round it up - file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) & - ~((sections.get(1).getDataAlign()-1)); + file_offset = (file_offset + (sections.get(1).getDataAlign() - 1)) & + ~((sections.get(1).getDataAlign() - 1)); // Calc file offsets for section data skipping null section for (int i = 1; i < sections.size(); i++) { ElfSection sect = sections.get(i); - file_offset = (file_offset + (sect.getDataAlign()-1)) & - ~((sect.getDataAlign()-1)); + file_offset = (file_offset + (sect.getDataAlign() - 1)) & + ~((sect.getDataAlign() - 1)); sect.setOffset(file_offset); file_offset += sect.getSize(); } // Align the section table - file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) & - ~((ElfSection.getShdrAlign()-1)); + file_offset = (file_offset + (ElfSection.getShdrAlign() - 1)) & + ~((ElfSection.getShdrAlign() - 1)); // Update the Elf Header with the offset of the first Elf64_Shdr // and the number of sections. @@ -249,24 +225,25 @@ elfContainer.close(); } + /** - * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF - * symbol table and ELF symbol table are created from BinaryContainer's symbol info. + * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF symbol + * table and ELF symbol table are created from BinaryContainer's symbol info. * * @param symbols */ - private ElfSymtab createELFSymbolTables(ArrayList sections, Collection symbols) { + private static ElfSymtab createELFSymbolTables(Collection symbols) { ElfSymtab symtab = new ElfSymtab(); // First, create the initial null symbol. This is a local symbol. - symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0); + symtab.addSymbolEntry("", (byte) 0, (byte) 0, Elf64_Shdr.SHN_UNDEF, 0, 0); // Now create ELF symbol entries for all symbols. for (Symbol symbol : symbols) { // Get the index of section this symbol is defined in. int secHdrIndex = symbol.getSection().getSectionId(); - ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize()); - symbol.setNativeSymbol((NativeSymbol)elfSymbol); + ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte) secHdrIndex, symbol.getOffset(), symbol.getSize()); + symbol.setNativeSymbol(elfSymbol); } return (symtab); } @@ -300,8 +277,7 @@ ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size()); /* - * For each of the symbols with associated relocation records, create a Elf relocation - * entry. + * For each of the symbols with associated relocation records, create a Elf relocation entry. */ for (Map.Entry> entry : relocationTable.entrySet()) { List relocs = entry.getValue(); @@ -319,69 +295,39 @@ return (elfRelocTable); } - private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) { + private static void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) { RelocType relocType = reloc.getType(); int elfRelocType = getELFRelocationType(relocType); - ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol(); + ElfSymbol sym = (ElfSymbol) symbol.getNativeSymbol(); int symno = sym.getIndex(); int sectindex = reloc.getSection().getSectionId(); int offset = reloc.getOffset(); int addend = 0; switch (relocType) { - case FOREIGN_CALL_DIRECT: case JAVA_CALL_DIRECT: case STUB_CALL_DIRECT: case FOREIGN_CALL_INDIRECT_GOT: { // Create relocation entry - // System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH"); addend = -4; // Size in bytes of the patch location // Relocation should be applied at the location after call operand offset = offset + reloc.getSize() + addend; break; } - case FOREIGN_CALL_DIRECT_FAR: { - // Create relocation entry - addend = -8; // Size in bytes of the patch location - // Relocation should be applied at the location after call operand - // 10 = 2 (jmp [r]) + 8 (imm64) - offset = offset + reloc.getSize() + addend - 2; - break; - } - case FOREIGN_CALL_INDIRECT: case JAVA_CALL_INDIRECT: - case STUB_CALL_INDIRECT: { - // Do nothing. - return; - } - case EXTERNAL_DATA_REFERENCE_FAR: { - // Create relocation entry + case METASPACE_GOT_REFERENCE: + case EXTERNAL_PLT_TO_GOT: { addend = -4; // Size of 32-bit address of the GOT /* * Relocation should be applied before the test instruction to the move instruction. - * offset points to the test instruction after the instruction that loads - * the address of polling page. So set the offset appropriately. + * reloc.getOffset() points to the test instruction after the instruction that loads the address of + * polling page. So set the offset appropriately. */ offset = offset + addend; break; } - case METASPACE_GOT_REFERENCE: - case EXTERNAL_PLT_TO_GOT: - case STATIC_STUB_TO_STATIC_METHOD: - case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { - addend = -4; // Size of 32-bit address of the GOT - /* - * Relocation should be applied before the test instruction to - * the move instruction. reloc.getOffset() points to the - * test instruction after the instruction that loads the - * address of polling page. So set the offset appropriately. - */ - offset = offset + addend; - break; - } - case EXTERNAL_GOT_TO_PLT: - case LOADTIME_ADDRESS: { + case EXTERNAL_GOT_TO_PLT: { // this is load time relocations break; } @@ -396,27 +342,17 @@ switch (ElfTargetInfo.getElfArch()) { case Elf64_Ehdr.EM_X86_64: // Return R_X86_64_* entries based on relocType - if (relocType == RelocType.FOREIGN_CALL_DIRECT || - relocType == RelocType.JAVA_CALL_DIRECT || + if (relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { elfRelocType = Elf64_Rela.R_X86_64_PLT32; } else if (relocType == RelocType.STUB_CALL_DIRECT) { elfRelocType = Elf64_Rela.R_X86_64_PC32; - } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { - elfRelocType = Elf64_Rela.R_X86_64_64; - } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || - relocType == RelocType.JAVA_CALL_INDIRECT || - relocType == RelocType.STUB_CALL_INDIRECT) { + } else if (relocType == RelocType.JAVA_CALL_INDIRECT) { elfRelocType = Elf64_Rela.R_X86_64_NONE; - } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { - elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL; } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || - relocType == RelocType.EXTERNAL_PLT_TO_GOT || - relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || - relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { + relocType == RelocType.EXTERNAL_PLT_TO_GOT) { elfRelocType = Elf64_Rela.R_X86_64_PC32; - } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || - relocType == RelocType.LOADTIME_ADDRESS) { + } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) { elfRelocType = Elf64_Rela.R_X86_64_64; } else { assert false : "Unhandled relocation type: " + relocType; @@ -428,9 +364,9 @@ return elfRelocType; } - private void createElfRelocSections(ArrayList sections, - ElfRelocTable elfRelocTable, - int symtabsectidx) { + private static void createElfRelocSections(ArrayList sections, + ElfRelocTable elfRelocTable, + int symtabsectidx) { // Grab count before we create new sections int count = sections.size(); @@ -439,15 +375,11 @@ if (elfRelocTable.getNumRelocs(i) > 0) { ElfSection sect = sections.get(i); String relname = ".rela" + sect.getName(); - ElfSection relocSection = createByteSection(sections, - relname, - elfRelocTable.getRelocData(i), - false, - 8, - 0, - Elf64_Shdr.SHT_RELA); - relocSection.setLink(symtabsectidx); - relocSection.setInfo(sect.getSectionId()); + ElfSection relocSection = createByteSection(sections, relname, + elfRelocTable.getRelocData(i), + false, 8, 0, Elf64_Shdr.SHT_RELA); + relocSection.setLink(symtabsectidx); + relocSection.setInfo(sect.getSectionId()); } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java Tue Sep 05 10:09:44 2017 -0700 @@ -53,11 +53,8 @@ import jdk.tools.jaotc.binformat.Relocation; import jdk.tools.jaotc.binformat.Relocation.RelocType; import jdk.tools.jaotc.binformat.Symbol; -import jdk.tools.jaotc.binformat.NativeSymbol; -import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.section_64; import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64; @@ -85,7 +82,7 @@ this.segmentSize = binContainer.getCodeSegmentSize(); } - private void createByteSection(ArrayListsections, + private void createByteSection(ArrayList sections, ByteContainer c, String sectName, String segName, int scnFlags) { if (c.getByteArray().length == 0) { @@ -102,24 +99,24 @@ sections.add(sect); // Record the section Id (0 relative) - c.setSectionId(sections.size()-1); + c.setSectionId(sections.size() - 1); // TODO: Clear out code section data to allow for GC // c.clear(); } - private void createCodeSection(ArrayListsections, CodeContainer c) { - createByteSection(sections, c, /*c.getContainerName()*/ "__text", "__TEXT", - section_64.S_ATTR_PURE_INSTRUCTIONS| + private void createCodeSection(ArrayList sections, CodeContainer c) { + createByteSection(sections, c, /* c.getContainerName() */ "__text", "__TEXT", + section_64.S_ATTR_PURE_INSTRUCTIONS | section_64.S_ATTR_SOME_INSTRUCTIONS); } - private void createReadOnlySection(ArrayListsections, ReadOnlyDataContainer c) { + private void createReadOnlySection(ArrayList sections, ReadOnlyDataContainer c) { createByteSection(sections, c, c.getContainerName(), "__TEXT", section_64.S_ATTR_SOME_INSTRUCTIONS); } - private void createReadWriteSection(ArrayListsections, ByteContainer c) { + private void createReadWriteSection(ArrayList sections, ByteContainer c) { createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR); } @@ -140,7 +137,7 @@ MachOHeader mh = new MachOHeader(); - ArrayList sections = new ArrayList(); + ArrayList sections = new ArrayList<>(); // Create Sections contained in the main Segment LC_SEGMENT_64 @@ -149,21 +146,19 @@ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); - createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); - createReadWriteSection(sections, binContainer.getMetadataGotContainer()); - createReadWriteSection(sections, binContainer.getMethodStateContainer()); - createReadWriteSection(sections, binContainer.getOopGotContainer()); - createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); + createReadOnlySection(sections, binContainer.getMethodMetadataContainer()); createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); createReadOnlySection(sections, binContainer.getConstantDataContainer()); createReadOnlySection(sections, binContainer.getConfigContainer()); - - // createExternalLinkage(); + createReadWriteSection(sections, binContainer.getKlassesGotContainer()); + createReadWriteSection(sections, binContainer.getCountersGotContainer()); + createReadWriteSection(sections, binContainer.getMetadataGotContainer()); + createReadWriteSection(sections, binContainer.getMethodStateContainer()); + createReadWriteSection(sections, binContainer.getOopGotContainer()); + createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); - createCodeSection(sections, binContainer.getExtLinkageContainer()); - createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); // Update the Header sizeofcmds size. // This doesn't include the Header struct size mh.setCmdSizes(4, segment_command_64.totalsize + @@ -175,14 +170,14 @@ // Initialize file offset for data past commands int file_offset = mach_header_64.totalsize + mh.getCmdSize(); // and round it up - file_offset = (file_offset + (sections.get(0).getAlign()-1)) & ~((sections.get(0).getAlign()-1)); + file_offset = (file_offset + (sections.get(0).getAlign() - 1)) & ~((sections.get(0).getAlign() - 1)); long address = 0; int segment_offset = file_offset; for (int i = 0; i < sections.size(); i++) { MachOSection sect = sections.get(i); - file_offset = (file_offset + (sect.getAlign()-1)) & ~((sect.getAlign()-1)); - address = (address + (sect.getAlign()-1)) & ~((sect.getAlign()-1)); + file_offset = (file_offset + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1)); + address = (address + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1)); sect.setOffset(file_offset); sect.setAddr(address); file_offset += sect.getSize(); @@ -199,7 +194,6 @@ segment_size, sections.size()); - MachOVersion vers = new MachOVersion(); // Get symbol data from BinaryContainer object's symbol tables @@ -213,7 +207,7 @@ // Create the Relocation Tables MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab); // Calculate file offset for relocation data - file_offset = (file_offset + (machORelocs.getAlign()-1)) & ~((machORelocs.getAlign()-1)); + file_offset = (file_offset + (MachORelocTable.getAlign() - 1)) & ~((MachORelocTable.getAlign() - 1)); // Update relocation sizing information in each section for (int i = 0; i < sections.size(); i++) { @@ -227,10 +221,9 @@ } // Calculate and set file offset for symbol table data - file_offset = (file_offset + (symtab.getAlign()-1)) & ~((symtab.getAlign()-1)); + file_offset = (file_offset + (MachOSymtab.getAlign() - 1)) & ~((MachOSymtab.getAlign() - 1)); symtab.setOffset(file_offset); - // Write Out Header machoContainer.writeBytes(mh.getArray()); // Write out first Segment @@ -259,12 +252,13 @@ // Write out the relocation tables for all sections for (int i = 0; i < sections.size(); i++) { - if (machORelocs.getNumRelocs(i) > 0) - machoContainer.writeBytes(machORelocs.getRelocData(i), machORelocs.getAlign()); + if (machORelocs.getNumRelocs(i) > 0) { + machoContainer.writeBytes(machORelocs.getRelocData(i), MachORelocTable.getAlign()); + } } // Write out data associated with LC_SYMTAB - machoContainer.writeBytes(symtab.getDataArray(), symtab.getAlign()); + machoContainer.writeBytes(symtab.getDataArray(), MachOSymtab.getAlign()); machoContainer.close(); } @@ -273,14 +267,14 @@ * Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO * symbol table and MachO symbol table are created from BinaryContainer's symbol info. * + * @param sections * @param symbols - * @param symtab */ - private MachOSymtab createMachOSymbolTables(ArrayListsections, - Collection symbols) { + private static MachOSymtab createMachOSymbolTables(ArrayList sections, + Collection symbols) { MachOSymtab symtab = new MachOSymtab(); // First, create the initial null symbol. This is a local symbol. - symtab.addSymbolEntry("", (byte)nlist_64.N_UNDF, (byte)0, (long)0); + symtab.addSymbolEntry("", (byte) nlist_64.N_UNDF, (byte) 0, 0); // Now create MachO symbol entries for all symbols. for (Symbol symbol : symbols) { @@ -290,14 +284,14 @@ long sectionAddr = sections.get(sectionId).getAddr(); MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(), - getMachOTypeOf(symbol), - (byte)sectionId, - symbol.getOffset() + sectionAddr); - symbol.setNativeSymbol((NativeSymbol)machoSymbol); + getMachOTypeOf(symbol), + (byte) sectionId, + symbol.getOffset() + sectionAddr); + symbol.setNativeSymbol(machoSymbol); } // Now that all symbols are enterred, update the - // symbol indexes. This is necessary since they will + // symbol indexes. This is necessary since they will // be reordered based on local, global and undefined. symtab.updateIndexes(); @@ -309,9 +303,9 @@ byte type = nlist_64.N_UNDF; // Global or Local - if (sym.getBinding() == Symbol.Binding.GLOBAL) + if (sym.getBinding() == Symbol.Binding.GLOBAL) { type = nlist_64.N_EXT; - + } // If Function or Data, add section type if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION || @@ -335,8 +329,7 @@ MachORelocTable machORelocTable = new MachORelocTable(sections.size()); /* - * For each of the symbols with associated relocation records, create a MachO relocation - * entry. + * For each of the symbols with associated relocation records, create a MachO relocation entry. */ for (Map.Entry> entry : relocationTable.entrySet()) { List relocs = entry.getValue(); @@ -354,11 +347,11 @@ return (machORelocTable); } - private void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) { + private static void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) { RelocType relocType = reloc.getType(); int machORelocType = getMachORelocationType(relocType); - MachOSymbol sym = (MachOSymbol)symbol.getNativeSymbol(); + MachOSymbol sym = (MachOSymbol) symbol.getNativeSymbol(); int symno = sym.getIndex(); int sectindex = reloc.getSection().getSectionId(); int offset = reloc.getOffset(); @@ -366,73 +359,39 @@ int length = 0; int isextern = 1; -/* - System.out.println("reloctype: " + relocType + " size is " + - reloc.getSize() + " offset is " + offset + - " Section Index is " + (sectindex) + - " Symbol Index is " + symno + - " Symbol Name is " + symbol.getName() + "\n"); -*/ - switch (relocType) { - case FOREIGN_CALL_DIRECT: case JAVA_CALL_DIRECT: case STUB_CALL_DIRECT: case FOREIGN_CALL_INDIRECT_GOT: { // Create relocation entry - // System.out.println("getMachORelocationType: PLT relocation type using X86_64_RELOC_BRANCH"); int addend = -4; // Size in bytes of the patch location // Relocation should be applied at the location after call operand offset = offset + reloc.getSize() + addend; - pcrel = 1; length = 2; + pcrel = 1; + length = 2; break; } - case FOREIGN_CALL_DIRECT_FAR: { - // Create relocation entry - int addend = -8; // Size in bytes of the patch location - // Relocation should be applied at the location after call operand - // 10 = 2 (jmp [r]) + 8 (imm64) - offset = offset + reloc.getSize() + addend - 2; - pcrel = 0; length = 3; - break; - } - case FOREIGN_CALL_INDIRECT: - case JAVA_CALL_INDIRECT: - case STUB_CALL_INDIRECT: { + case JAVA_CALL_INDIRECT: { // Do nothing. return; } - case EXTERNAL_DATA_REFERENCE_FAR: { - // Create relocation entry + case METASPACE_GOT_REFERENCE: + case EXTERNAL_PLT_TO_GOT: { int addend = -4; // Size of 32-bit address of the GOT /* * Relocation should be applied before the test instruction to the move instruction. - * offset points to the test instruction after the instruction that loads - * the address of polling page. So set the offset appropriately. + * reloc.getOffset() points to the test instruction after the instruction that loads the address of + * polling page. So set the offset appropriately. */ offset = offset + addend; - pcrel = 0; length = 2; + pcrel = 1; + length = 2; break; } - case METASPACE_GOT_REFERENCE: - case EXTERNAL_PLT_TO_GOT: - case STATIC_STUB_TO_STATIC_METHOD: - case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { - int addend = -4; // Size of 32-bit address of the GOT - /* - * Relocation should be applied before the test instruction to - * the move instruction. reloc.getOffset() points to the - * test instruction after the instruction that loads the - * address of polling page. So set the offset appropriately. - */ - offset = offset + addend; - pcrel = 1; length = 2; - break; - } - case EXTERNAL_GOT_TO_PLT: - case LOADTIME_ADDRESS: { + case EXTERNAL_GOT_TO_PLT: { // this is load time relocations - pcrel = 0; length = 3; + pcrel = 0; + length = 3; break; } default: @@ -448,20 +407,17 @@ switch (MachOTargetInfo.getMachOArch()) { case mach_header_64.CPU_TYPE_X86_64: // Return X86_64_RELOC_* entries based on relocType - if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { + if (relocType == RelocType.JAVA_CALL_DIRECT || + relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { machORelocType = reloc_info.X86_64_RELOC_BRANCH; } else if (relocType == RelocType.STUB_CALL_DIRECT) { machORelocType = reloc_info.X86_64_RELOC_BRANCH; - } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { - machORelocType = reloc_info.X86_64_RELOC_UNSIGNED; - } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) { + } else if (relocType == RelocType.JAVA_CALL_INDIRECT) { machORelocType = reloc_info.X86_64_RELOC_NONE; - } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { - machORelocType = reloc_info.X86_64_RELOC_GOT; - } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || - relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { + } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || + relocType == RelocType.EXTERNAL_PLT_TO_GOT) { machORelocType = reloc_info.X86_64_RELOC_BRANCH; - } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) { + } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) { machORelocType = reloc_info.X86_64_RELOC_UNSIGNED; } else { assert false : "Unhandled relocation type: " + relocType; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachO.java Tue Sep 05 10:09:44 2017 -0700 @@ -23,10 +23,10 @@ package jdk.tools.jaotc.binformat.macho; +//@formatter:off /** * - * Support for the creation of Mach-o Object files. - * Current support is limited to 64 bit x86_64. + * Support for the creation of Mach-o Object files. Current support is limited to 64 bit x86_64. * * File Format Overview: * @@ -38,12 +38,12 @@ * (which each include multiple Sections) */ -public class MachO { +final class MachO { /** * mach_header_64 structure defines */ - public enum mach_header_64 { + enum mach_header_64 { magic( 0, 4), cputype( 4, 4), cpusubtype( 8, 4), @@ -53,49 +53,49 @@ flags(24, 4), reserved(28, 4); - public final int off; - public final int sz; + final int off; + final int sz; mach_header_64(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 32; + static int totalsize = 32; /** * mach_header_64 defines */ - public static final int MH_MAGIC = 0xfeedface; - public static final int MH_MAGIC_64 = 0xfeedfacf; - public static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000; + static final int MH_MAGIC = 0xfeedface; + static final int MH_MAGIC_64 = 0xfeedfacf; + static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000; /** * filetype */ - public static final int MH_OBJECT = 0x1; + static final int MH_OBJECT = 0x1; /** * cputype */ - public static final int CPU_TYPE_ANY = -1; - public static final int CPU_ARCH_ABI64 = 0x1000000; - public static final int CPU_TYPE_X86_64 = 0x1000007; - public static final int CPU_TYPE_ARM64 = 0x100000c; + static final int CPU_TYPE_ANY = -1; + static final int CPU_ARCH_ABI64 = 0x1000000; + static final int CPU_TYPE_X86_64 = 0x1000007; + static final int CPU_TYPE_ARM64 = 0x100000c; /** * cpusubtype */ - public static final int CPU_SUBTYPE_I386_ALL = 3; - public static final int CPU_SUBTYPE_ARM64_ALL = 0; - public static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0; - public static final int CPU_SUBTYPE_BIG_ENDIAN = 1; + static final int CPU_SUBTYPE_I386_ALL = 3; + static final int CPU_SUBTYPE_ARM64_ALL = 0; + static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0; + static final int CPU_SUBTYPE_BIG_ENDIAN = 1; } /** * segment_command_64 structure defines */ - public enum segment_command_64 { + enum segment_command_64 { cmd( 0, 4), cmdsize( 4, 4), segname( 8,16), @@ -108,23 +108,23 @@ nsects(64, 4), flags(68, 4); - public final int off; - public final int sz; + final int off; + final int sz; segment_command_64(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 72; + static int totalsize = 72; - public static final int LC_SEGMENT_64 = 0x19; + static final int LC_SEGMENT_64 = 0x19; } /** * section_64 structure defines */ - public enum section_64 { + enum section_64 { sectname( 0,16), segname(16,16), addr(32, 8), @@ -138,49 +138,49 @@ reserved2(72, 4), reserved3(76, 4); - public final int off; - public final int sz; + final int off; + final int sz; section_64(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 80; + static int totalsize = 80; - public static int S_REGULAR = 0x0; - public static int S_CSTRING_LITERALS = 0x2; - public static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000; - public static int S_ATTR_SOME_INSTRUCTIONS = 0x400; + static int S_REGULAR = 0x0; + static int S_CSTRING_LITERALS = 0x2; + static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000; + static int S_ATTR_SOME_INSTRUCTIONS = 0x400; } /** * version_min_command structure defines */ - public enum version_min_command { + enum version_min_command { cmd( 0, 4), cmdsize( 4, 4), version( 8, 4), sdk(12, 4); - public final int off; - public final int sz; + final int off; + final int sz; version_min_command(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 16; + static int totalsize = 16; - public static final int LC_VERSION_MIN_MACOSX = 0x24; - public static final int LC_VERSION_MIN_IPHONEOS = 0x25; + static final int LC_VERSION_MIN_MACOSX = 0x24; + static final int LC_VERSION_MIN_IPHONEOS = 0x25; } /** * symtab_command structure defines */ - public enum symtab_command { + enum symtab_command { cmd( 0, 4), cmdsize( 4, 4), symoff( 8, 4), @@ -188,17 +188,17 @@ stroff(16, 4), strsize(20, 4); - public final int off; - public final int sz; + final int off; + final int sz; symtab_command(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 24; + static int totalsize = 24; - public static final int LC_SYMTAB = 0x2; + static final int LC_SYMTAB = 0x2; } /** @@ -206,33 +206,33 @@ * * nlist_64 structure defines */ - public enum nlist_64 { + enum nlist_64 { n_strx( 0, 4), n_type( 4, 1), n_sect( 5, 1), n_desc( 6, 2), n_value( 8, 8); - public final int off; - public final int sz; + final int off; + final int sz; nlist_64(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 16; + static int totalsize = 16; - public static final int N_EXT = 0x1; - public static final int N_TYPE = 0xe; - public static final int N_UNDF = 0x0; - public static final int N_SECT = 0xe; + static final int N_EXT = 0x1; + static final int N_TYPE = 0xe; + static final int N_UNDF = 0x0; + static final int N_SECT = 0xe; } /** * dysymtab_command structure defines */ - public enum dysymtab_command { + enum dysymtab_command { cmd( 0, 4), cmdsize( 4, 4), ilocalsym( 8, 4), @@ -254,54 +254,55 @@ locreloff(72, 4), nlocrel(76, 4); - public final int off; - public final int sz; + final int off; + final int sz; dysymtab_command(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 80; + static int totalsize = 80; - public static final int LC_DYSYMTAB = 0xb; + static final int LC_DYSYMTAB = 0xb; } /** * relocation_info structure defines */ - public enum reloc_info { + enum reloc_info { r_address( 0, 4), r_relocinfo( 4, 4); - public final int off; - public final int sz; + final int off; + final int sz; reloc_info(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 8; + static int totalsize = 8; - public static final int REL_SYMNUM_MASK = 0xffffff; - public static final int REL_SYMNUM_SHIFT = 0x0; - public static final int REL_PCREL_MASK = 0x1; - public static final int REL_PCREL_SHIFT = 0x18; - public static final int REL_LENGTH_MASK = 0x3; - public static final int REL_LENGTH_SHIFT = 0x19; - public static final int REL_EXTERN_MASK = 0x1; - public static final int REL_EXTERN_SHIFT = 0x1b; - public static final int REL_TYPE_MASK = 0xf; - public static final int REL_TYPE_SHIFT = 0x1c; + static final int REL_SYMNUM_MASK = 0xffffff; + static final int REL_SYMNUM_SHIFT = 0x0; + static final int REL_PCREL_MASK = 0x1; + static final int REL_PCREL_SHIFT = 0x18; + static final int REL_LENGTH_MASK = 0x3; + static final int REL_LENGTH_SHIFT = 0x19; + static final int REL_EXTERN_MASK = 0x1; + static final int REL_EXTERN_SHIFT = 0x1b; + static final int REL_TYPE_MASK = 0xf; + static final int REL_TYPE_SHIFT = 0x1c; /* reloc_type_x86_64 defines */ - public static final int X86_64_RELOC_NONE = 0x0; - public static final int X86_64_RELOC_BRANCH = 0x2; - public static final int X86_64_RELOC_GOT = 0x4; - public static final int X86_64_RELOC_GOT_LOAD = 0x3; - public static final int X86_64_RELOC_SIGNED = 0x1; - public static final int X86_64_RELOC_UNSIGNED = 0x0; + static final int X86_64_RELOC_NONE = 0x0; + static final int X86_64_RELOC_BRANCH = 0x2; + static final int X86_64_RELOC_GOT = 0x4; + static final int X86_64_RELOC_GOT_LOAD = 0x3; + static final int X86_64_RELOC_SIGNED = 0x1; + static final int X86_64_RELOC_UNSIGNED = 0x0; } } +//@formatter:on diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOByteBuffer.java Tue Sep 05 10:09:44 2017 -0700 @@ -23,21 +23,19 @@ package jdk.tools.jaotc.binformat.macho; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.macho.MachOTargetInfo; -import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; -public class MachOByteBuffer { +final class MachOByteBuffer { - public static ByteBuffer allocate(int size) { + static ByteBuffer allocate(int size) { ByteBuffer buf = ByteBuffer.allocate(size); - if (MachOTargetInfo.getMachOEndian() == - MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN) + if (MachOTargetInfo.getMachOEndian() == MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN) { buf.order(ByteOrder.LITTLE_ENDIAN); - else + } else { buf.order(ByteOrder.BIG_ENDIAN); + } return (buf); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -26,14 +26,13 @@ import java.io.File; import java.io.FileOutputStream; -public class MachOContainer { +final class MachOContainer { - File outputFile; - FileOutputStream outputStream; - long fileOffset; + private final File outputFile; + private FileOutputStream outputStream; + private long fileOffset; - public MachOContainer(String fileName) { - String baseName; + MachOContainer(String fileName) { outputFile = new File(fileName); if (outputFile.exists()) { @@ -48,7 +47,7 @@ fileOffset = 0; } - public void close() { + void close() { try { outputStream.close(); } catch (Exception e) { @@ -56,7 +55,7 @@ } } - public void writeBytes(byte [] bytes) { + void writeBytes(byte[] bytes) { try { outputStream.write(bytes); } catch (Exception e) { @@ -66,10 +65,10 @@ } // Write bytes to output file with up front alignment padding - public void writeBytes(byte [] bytes, int alignment) { + void writeBytes(byte[] bytes, int alignment) { try { // Pad to alignment - while ((fileOffset & (long)(alignment-1)) != 0) { + while ((fileOffset & (alignment - 1)) != 0) { outputStream.write(0); fileOffset++; } @@ -80,4 +79,3 @@ fileOffset += bytes.length; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachODySymtab.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,16 +24,14 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachODySymtab { - ByteBuffer dysymtab; +final class MachODySymtab { + private final ByteBuffer dysymtab; - public MachODySymtab(int nlocal, int nglobal, int nundef) { + MachODySymtab(int nlocal, int nglobal, int nundef) { dysymtab = MachOByteBuffer.allocate(dysymtab_command.totalsize); dysymtab.putInt(dysymtab_command.cmd.off, dysymtab_command.LC_DYSYMTAB); @@ -42,13 +40,11 @@ dysymtab.putInt(dysymtab_command.nlocalsym.off, nlocal); dysymtab.putInt(dysymtab_command.iextdefsym.off, nlocal); dysymtab.putInt(dysymtab_command.nextdefsym.off, nglobal); - dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal+nglobal); + dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal + nglobal); dysymtab.putInt(dysymtab_command.nundefsym.off, nundef); } - public byte[] getArray() { + byte[] getArray() { return dysymtab.array(); } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOHeader.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,17 +24,15 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; import jdk.tools.jaotc.binformat.macho.MachOTargetInfo; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachOHeader { - ByteBuffer header; +final class MachOHeader { + private final ByteBuffer header; - public MachOHeader() { + MachOHeader() { header = MachOByteBuffer.allocate(mach_header_64.totalsize); header.putInt(mach_header_64.magic.off, mach_header_64.MH_MAGIC_64); @@ -44,17 +42,16 @@ header.putInt(mach_header_64.filetype.off, mach_header_64.MH_OBJECT); } - public void setCmdSizes(int ncmds, int sizeofcmds) { + void setCmdSizes(int ncmds, int sizeofcmds) { header.putInt(mach_header_64.ncmds.off, ncmds); header.putInt(mach_header_64.sizeofcmds.off, sizeofcmds); } - public int getCmdSize() { + int getCmdSize() { return (header.getInt(mach_header_64.sizeofcmds.off)); } - public byte[] getArray() { + byte[] getArray() { return header.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocEntry.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,42 +24,31 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.reloc_info; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachORelocEntry { - ByteBuffer entry; +final class MachORelocEntry { + private final ByteBuffer entry; - public MachORelocEntry(int offset, - int symno, - int pcrel, - int length, - int isextern, - int type) { + MachORelocEntry(int offset, int symno, int pcrel, int length, int isextern, int type) { entry = MachOByteBuffer.allocate(reloc_info.totalsize); entry.putInt(reloc_info.r_address.off, offset); // Encode and store the relocation entry bitfields + // @formatter:off entry.putInt(reloc_info.r_relocinfo.off, - ((symno & reloc_info.REL_SYMNUM_MASK) - << reloc_info.REL_SYMNUM_SHIFT) | - ((pcrel & reloc_info.REL_PCREL_MASK) - << reloc_info.REL_PCREL_SHIFT) | - ((length & reloc_info.REL_LENGTH_MASK) - << reloc_info.REL_LENGTH_SHIFT) | - ((isextern & reloc_info.REL_EXTERN_MASK) - << reloc_info.REL_EXTERN_SHIFT) | - ((type & reloc_info.REL_TYPE_MASK) - << reloc_info.REL_TYPE_SHIFT)); + ((symno & reloc_info.REL_SYMNUM_MASK) << reloc_info.REL_SYMNUM_SHIFT) | + ((pcrel & reloc_info.REL_PCREL_MASK) << reloc_info.REL_PCREL_SHIFT) | + ((length & reloc_info.REL_LENGTH_MASK) << reloc_info.REL_LENGTH_SHIFT) | + ((isextern & reloc_info.REL_EXTERN_MASK) << reloc_info.REL_EXTERN_SHIFT) | + ((type & reloc_info.REL_TYPE_MASK) << reloc_info.REL_TYPE_SHIFT)); + // @formatter:on } - public byte[] getArray() { + byte[] getArray() { return entry.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachORelocTable.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,56 +25,43 @@ import java.util.ArrayList; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.macho.MachORelocEntry; -import jdk.tools.jaotc.binformat.macho.MachOTargetInfo; import jdk.tools.jaotc.binformat.macho.MachO.reloc_info; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachORelocTable { - ArrayList> relocEntries; +final class MachORelocTable { + private final ArrayList> relocEntries; int fileOffset; - public MachORelocTable(int numsects) { - relocEntries = new ArrayList>(numsects); - for (int i = 0; i < numsects; i++) + MachORelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { relocEntries.add(new ArrayList()); + } } - public void createRelocationEntry(int sectindex, - int offset, - int symno, - int pcrel, - int length, - int isextern, - int type) { - - MachORelocEntry entry = new MachORelocEntry(offset, - symno, - pcrel, - length, - isextern, - type); + void createRelocationEntry(int sectindex, int offset, int symno, int pcrel, int length, int isextern, int type) { + MachORelocEntry entry = new MachORelocEntry(offset, symno, pcrel, length, isextern, type); relocEntries.get(sectindex).add(entry); } - public int getAlign() { + static int getAlign() { return (4); } - public int getNumRelocs(int section_index) { + int getNumRelocs(int section_index) { return relocEntries.get(section_index).size(); } // Return the relocation entries for a single section - // or null if no entries added to section - public byte [] getRelocData(int section_index) { + // or null if no entries added to section + byte[] getRelocData(int section_index) { ArrayList entryList = relocEntries.get(section_index); - if (entryList.size() == 0) + if (entryList.size() == 0) { return null; - + } ByteBuffer relocData = MachOByteBuffer.allocate(entryList.size() * reloc_info.totalsize); // Copy each entry to a single ByteBuffer @@ -86,4 +73,3 @@ return (relocData.array()); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSection.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,41 +24,36 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.section_64; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachOSection { - ByteBuffer section; - byte [] data; - boolean hasrelocations; +final class MachOSection { + private final ByteBuffer section; + private final byte[] data; + private final boolean hasrelocations; - public MachOSection(String sectName, String segName, byte [] sectData, int sectFlags, boolean hasRelocations, int align) { + MachOSection(String sectName, String segName, byte[] sectData, int sectFlags, boolean hasRelocations, int align) { section = MachOByteBuffer.allocate(section_64.totalsize); // TODO: Hotspot uses long section names. - // They are getting truncated. - // Is this a problem?? + // They are getting truncated. + // Is this a problem?? byte[] sectNameBytes = sectName.getBytes(); - int sectNameMax = section_64.sectname.sz < sectNameBytes.length ? - section_64.sectname.sz : sectNameBytes.length; + int sectNameMax = section_64.sectname.sz < sectNameBytes.length ? section_64.sectname.sz : sectNameBytes.length; - for (int i = 0; i < sectNameMax; i++) - section.put(section_64.sectname.off+i, sectNameBytes[i]); - + for (int i = 0; i < sectNameMax; i++) { + section.put(section_64.sectname.off + i, sectNameBytes[i]); + } byte[] segNameBytes = segName.getBytes(); - int segNameMax = section_64.segname.sz < segNameBytes.length ? - section_64.segname.sz : segNameBytes.length; + int segNameMax = section_64.segname.sz < segNameBytes.length ? section_64.segname.sz : segNameBytes.length; - for (int i = 0; i < segNameMax; i++) - section.put(section_64.segname.off+i, segNameBytes[i]); - + for (int i = 0; i < segNameMax; i++) { + section.put(section_64.segname.off + i, segNameBytes[i]); + } section.putLong(section_64.size.off, sectData.length); - section.putInt(section_64.align.off, - 31 - Integer.numberOfLeadingZeros(align)); + section.putInt(section_64.align.off, 31 - Integer.numberOfLeadingZeros(align)); section.putInt(section_64.flags.off, sectFlags); @@ -67,49 +62,47 @@ hasrelocations = hasRelocations; } - public long getSize() { + long getSize() { return section.getLong(section_64.size.off); } - public int getAlign() { + int getAlign() { return (1 << section.getInt(section_64.align.off)); } - public byte[] getArray() { + byte[] getArray() { return section.array(); } - public byte[] getDataArray() { + byte[] getDataArray() { return data; } - public void setAddr(long addr) { + void setAddr(long addr) { section.putLong(section_64.addr.off, addr); } - public long getAddr() { + long getAddr() { return (section.getLong(section_64.addr.off)); } - public void setOffset(int offset) { + void setOffset(int offset) { section.putInt(section_64.offset.off, offset); } - public int getOffset() { + int getOffset() { return (section.getInt(section_64.offset.off)); } - public void setReloff(int offset) { + void setReloff(int offset) { section.putInt(section_64.reloff.off, offset); } - public void setRelcount(int count) { + void setRelcount(int count) { section.putInt(section_64.nreloc.off, count); } - public boolean hasRelocations() { + boolean hasRelocations() { return hasrelocations; } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSegment.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,9 +24,7 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; @@ -52,5 +50,3 @@ return segment.array(); } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,17 +24,15 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.NativeSymbol; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachOSymbol extends NativeSymbol { - ByteBuffer sym; +final class MachOSymbol extends NativeSymbol { + private final ByteBuffer sym; - public MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) { + MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) { super(symbolindex); sym = MachOByteBuffer.allocate(nlist_64.totalsize); @@ -42,13 +40,12 @@ sym.put(nlist_64.n_type.off, type); // Section indexes start at 1 but we manage the index internally // as 0 relative - sym.put(nlist_64.n_sect.off, (byte)(sectindex+1)); - sym.putChar(nlist_64.n_desc.off, (char )0); + sym.put(nlist_64.n_sect.off, (byte) (sectindex + 1)); + sym.putChar(nlist_64.n_desc.off, (char) 0); sym.putLong(nlist_64.n_value.off, offset); } - public byte[] getArray() { + byte[] getArray() { return sym.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOSymtab.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,50 +24,42 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.ArrayList; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; import jdk.tools.jaotc.binformat.macho.MachOSymbol; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachOSymtab { +final class MachOSymtab { /** * ByteBuffer holding the LC_SYMTAB command contents */ - ByteBuffer symtabCmd; + private final ByteBuffer symtabCmd; + + private int symtabDataSize; - /** - * ByteBuffer holding the symbol table entries and strings - */ - ByteBuffer symtabData; - - int symtabDataSize; - - ArrayListlocalSymbols = new ArrayList(); - ArrayListglobalSymbols = new ArrayList(); - ArrayListundefSymbols = new ArrayList(); + private final ArrayList localSymbols = new ArrayList<>(); + private final ArrayList globalSymbols = new ArrayList<>(); + private final ArrayList undefSymbols = new ArrayList<>(); /** * number of symbols added */ - int symbolCount; + private int symbolCount; /** * String holding symbol table strings */ - private StringBuilder strTabContent = new StringBuilder(); + private final StringBuilder strTabContent = new StringBuilder(); /** - * Keeps track of bytes in string table since strTabContent.length() - * is number of chars, not bytes. + * Keeps track of bytes in string table since strTabContent.length() is number of chars, not bytes. */ private int strTabNrOfBytes = 0; - public MachOSymtab() { + MachOSymtab() { symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize); symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB); @@ -77,11 +69,11 @@ } - public int getAlign() { + static int getAlign() { return (4); } - public MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) { + MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) { // Get the current symbol index and append symbol name to string table. int index; MachOSymbol sym; @@ -109,7 +101,7 @@ case nlist_64.N_UNDF: // null symbol localSymbols.add(sym); break; - case nlist_64.N_SECT|nlist_64.N_EXT: + case nlist_64.N_SECT | nlist_64.N_EXT: globalSymbols.add(sym); break; default: @@ -121,30 +113,30 @@ return (sym); } - public void setOffset(int symoff) { + void setOffset(int symoff) { symtabCmd.putInt(symtab_command.symoff.off, symoff); } // Update the symbol indexes once all symbols have been added. // This is required since we'll be reordering the symbols in the // file to be in the order of Local, global and Undefined. - public void updateIndexes() { + void updateIndexes() { int index = 0; // Update the local symbol indexes - for (int i = 0; i < localSymbols.size(); i++ ) { + for (int i = 0; i < localSymbols.size(); i++) { MachOSymbol sym = localSymbols.get(i); sym.setIndex(index++); } // Update the global symbol indexes - for (int i = 0; i < globalSymbols.size(); i++ ) { + for (int i = 0; i < globalSymbols.size(); i++) { MachOSymbol sym = globalSymbols.get(i); sym.setIndex(index++); } // Update the undefined symbol indexes - for (int i = index; i < undefSymbols.size(); i++ ) { + for (int i = index; i < undefSymbols.size(); i++) { MachOSymbol sym = undefSymbols.get(i); sym.setIndex(index++); } @@ -152,7 +144,7 @@ // Update LC_SYMTAB command fields based on the number of symbols added // return the file size taken up by symbol table entries and strings - public int calcSizes() { + int calcSizes() { int stroff; stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount); @@ -164,42 +156,49 @@ return (symtabDataSize); } - public int getNumLocalSyms() { return localSymbols.size(); } - public int getNumGlobalSyms() { return globalSymbols.size(); } - public int getNumUndefSyms() { return undefSymbols.size(); } + int getNumLocalSyms() { + return localSymbols.size(); + } - public byte[] getCmdArray() { + int getNumGlobalSyms() { + return globalSymbols.size(); + } + + int getNumUndefSyms() { + return undefSymbols.size(); + } + + byte[] getCmdArray() { return symtabCmd.array(); } // Create a single byte array that contains the symbol table entries // and string table - public byte[] getDataArray() { - int index = 0; - symtabData = MachOByteBuffer.allocate(symtabDataSize); - byte [] retarray; + byte[] getDataArray() { + ByteBuffer symtabData = MachOByteBuffer.allocate(symtabDataSize); + byte[] retarray; // Add the local symbols - for (int i = 0; i < localSymbols.size(); i++ ) { + for (int i = 0; i < localSymbols.size(); i++) { MachOSymbol sym = localSymbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } // Add the global symbols - for (int i = 0; i < globalSymbols.size(); i++ ) { + for (int i = 0; i < globalSymbols.size(); i++) { MachOSymbol sym = globalSymbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } // Add the undefined symbols - for (int i = 0; i < undefSymbols.size(); i++ ) { + for (int i = 0; i < undefSymbols.size(); i++) { MachOSymbol sym = undefSymbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } // Add the stringtable - byte [] strs = strTabContent.toString().getBytes(); + byte[] strs = strTabContent.toString().getBytes(); symtabData.put(strs); retarray = symtabData.array(); @@ -207,5 +206,3 @@ return (retarray); } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOTargetInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,14 +24,13 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; /** * Class that abstracts MACH-O target details. * */ -public class MachOTargetInfo { +final class MachOTargetInfo { /** * Target architecture and subtype. */ @@ -68,20 +67,19 @@ osName = System.getProperty("os.name").toLowerCase(); } - public static int getMachOArch() { + static int getMachOArch() { return arch; } - public static int getMachOSubArch() { + static int getMachOSubArch() { return subarch; } - public static int getMachOEndian() { + static int getMachOEndian() { return endian; } - public static String getOsName() { + static String getOsName() { return osName; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/MachOVersion.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,16 +24,14 @@ package jdk.tools.jaotc.binformat.macho; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.macho.MachO; import jdk.tools.jaotc.binformat.macho.MachO.version_min_command; import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; -public class MachOVersion { - ByteBuffer version; +final class MachOVersion { + private final ByteBuffer version; - public MachOVersion() { + MachOVersion() { version = MachOByteBuffer.allocate(version_min_command.totalsize); version.putInt(version_min_command.cmd.off, version_min_command.LC_VERSION_MIN_MACOSX); @@ -42,8 +40,7 @@ version.putInt(version_min_command.sdk.off, 0); /* N/A SDK */ } - public byte[] getArray() { + byte[] getArray() { return version.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/JPECoffRelocObject.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,13 +24,11 @@ package jdk.tools.jaotc.binformat.pecoff; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import jdk.tools.jaotc.binformat.Container; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; import jdk.tools.jaotc.binformat.CodeContainer; @@ -38,11 +36,9 @@ import jdk.tools.jaotc.binformat.Relocation; import jdk.tools.jaotc.binformat.Relocation.RelocType; import jdk.tools.jaotc.binformat.Symbol; -import jdk.tools.jaotc.binformat.NativeSymbol; import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol; import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER; @@ -56,71 +52,53 @@ private final PECoffContainer pecoffContainer; - private final int segmentSize; + private final int sectionAlignment; - public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) { + public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName) { this.binContainer = binContainer; - this.pecoffContainer = new PECoffContainer(outputFileName, aotVersion); - this.segmentSize = binContainer.getCodeSegmentSize(); - if (segmentSize != 64) { - System.out.println("binContainer alignment size not 64 bytes, update JPECoffRelocObject"); - } + this.pecoffContainer = new PECoffContainer(outputFileName); + this.sectionAlignment = binContainer.getCodeSegmentSize(); } - private PECoffSection createByteSection(ArrayListsections, - String sectName, - byte [] scnData, - boolean hasRelocs, - int scnFlags) { + private static PECoffSection createByteSection(ArrayList sections, String sectName, byte[] scnData, + boolean hasRelocs, int scnFlags, int sectAlign) { - PECoffSection sect = new PECoffSection(sectName, - scnData, - scnFlags, - hasRelocs, - sections.size()); + PECoffSection sect = new PECoffSection(sectName, scnData, scnFlags, sectAlign, hasRelocs, sections.size()); // Add this section to our list sections.add(sect); return (sect); } - private void createByteSection(ArrayListsections, - ByteContainer c, int scnFlags) { + private static void createByteSection(ArrayList sections, ByteContainer c, int scnFlags, int sectAlign) { PECoffSection sect; boolean hasRelocs = c.hasRelocations(); byte[] scnData = c.getByteArray(); - sect = createByteSection(sections, c.getContainerName(), - scnData, hasRelocs, - scnFlags); + sect = createByteSection(sections, c.getContainerName(), scnData, hasRelocs, scnFlags, sectAlign); c.setSectionId(sect.getSectionId()); } - private void createCodeSection(ArrayListsections, CodeContainer c) { - createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | - IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | - IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES | - IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE); + private void createCodeSection(ArrayList sections, CodeContainer c) { + int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE; + createByteSection(sections, c, scnFlags, sectionAlignment); + } + + private void createReadOnlySection(ArrayList sections, ReadOnlyDataContainer c) { + int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA; + createByteSection(sections, c, scnFlags, sectionAlignment); } - private void createReadOnlySection(ArrayListsections, ReadOnlyDataContainer c) { - createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | - IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES | - IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA); - } + private void createReadWriteSection(ArrayList sections, ByteContainer c) { + int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE; - private void createReadWriteSection(ArrayListsections, ByteContainer c) { - int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | - IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE | - IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES; - - if (c.getByteArray().length > 0) + if (c.getByteArray().length > 0) { scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA; - else + } else { scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA; - - createByteSection(sections, c, scnFlags); + } + createByteSection(sections, c, scnFlags, sectionAlignment); } /** @@ -131,7 +109,7 @@ * @throws IOException throws {@code IOException} as a result of file system access failures. */ public void createPECoffRelocObject(Map> relocationTable, Collection symbols) throws IOException { - ArrayList sections = new ArrayList(); + ArrayList sections = new ArrayList<>(); // Create text section createCodeSection(sections, binContainer.getCodeContainer()); @@ -139,51 +117,45 @@ createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); - createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); - createReadWriteSection(sections, binContainer.getMetadataGotContainer()); - createReadWriteSection(sections, binContainer.getMethodStateContainer()); - createReadWriteSection(sections, binContainer.getOopGotContainer()); - createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); + createReadOnlySection(sections, binContainer.getMethodMetadataContainer()); createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); createReadOnlySection(sections, binContainer.getConstantDataContainer()); createReadOnlySection(sections, binContainer.getConfigContainer()); - - // createExternalLinkage(); - - createCodeSection(sections, binContainer.getExtLinkageContainer()); + createReadWriteSection(sections, binContainer.getKlassesGotContainer()); + createReadWriteSection(sections, binContainer.getCountersGotContainer()); + createReadWriteSection(sections, binContainer.getMetadataGotContainer()); + createReadWriteSection(sections, binContainer.getMethodStateContainer()); + createReadWriteSection(sections, binContainer.getOopGotContainer()); createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); // Allocate PECoff Header PECoffHeader header = new PECoffHeader(); // Get PECoff symbol data from BinaryContainer object's symbol tables - PECoffSymtab symtab = createPECoffSymbolTables(sections, symbols); + PECoffSymtab symtab = createPECoffSymbolTables(symbols); // Add Linker Directives Section - createByteSection(sections, ".drectve", - symtab.getDirectiveArray(), false, - IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | - IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE | - IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_1BYTES); + int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE; + createByteSection(sections, ".drectve", symtab.getDirectiveArray(), false, scnFlags, 1 /* 1 byte alignment */); // Create the Relocation Tables PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable); // File Output Order // - // HEADER (Need address of Symbol Table + symbol count) - // SECTIONS (Need pointer to Section Data, Relocation Table) - // DIRECTIVES - // SYMBOL TABLE - // SYMBOLS - // SECTION DATA - // RELOCATION TABLE + // HEADER (Need address of Symbol Table + symbol count) + // SECTIONS (Need pointer to Section Data, Relocation Table) + // DIRECTIVES + // SYMBOL TABLE + // SYMBOLS + // SECTION DATA + // RELOCATION TABLE // Calculate Offset for Symbol table int file_offset = IMAGE_FILE_HEADER.totalsize + - (IMAGE_SECTION_HEADER.totalsize*sections.size()); + (IMAGE_SECTION_HEADER.totalsize * sections.size()); // Update Header fields header.setSectionCount(sections.size()); @@ -194,14 +166,14 @@ file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) + symtab.getStrtabSize()); // And round it up - file_offset = (file_offset + (sections.get(0).getDataAlign()-1)) & - ~((sections.get(0).getDataAlign()-1)); + file_offset = (file_offset + (sections.get(0).getDataAlign() - 1)) & + ~((sections.get(0).getDataAlign() - 1)); // Calc file offsets for section data for (int i = 0; i < sections.size(); i++) { PECoffSection sect = sections.get(i); - file_offset = (file_offset + (sect.getDataAlign()-1)) & - ~((sect.getDataAlign()-1)); + file_offset = (file_offset + (sect.getDataAlign() - 1)) & + ~((sect.getDataAlign() - 1)); sect.setOffset(file_offset); file_offset += sect.getSize(); } @@ -214,7 +186,9 @@ sect.setReloff(file_offset); sect.setRelcount(nreloc); // extended relocations add an addition entry - if (nreloc > 0xFFFF) nreloc++; + if (nreloc > 0xFFFF) { + nreloc++; + } file_offset += (nreloc * IMAGE_RELOCATION.totalsize); } } @@ -253,7 +227,7 @@ * * @param symbols */ - private PECoffSymtab createPECoffSymbolTables(ArrayList sections, Collection symbols) { + private static PECoffSymtab createPECoffSymbolTables(Collection symbols) { PECoffSymtab symtab = new PECoffSymtab(); // First, create the initial null symbol. This is a local symbol. @@ -263,8 +237,8 @@ for (Symbol symbol : symbols) { // Get the index of section this symbol is defined in. int secHdrIndex = symbol.getSection().getSectionId(); - PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize()); - symbol.setNativeSymbol((NativeSymbol)pecoffSymbol); + PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte) secHdrIndex, symbol.getOffset()); + symbol.setNativeSymbol(pecoffSymbol); } return (symtab); } @@ -291,13 +265,11 @@ * @param sections * @param relocationTable */ - private PECoffRelocTable createPECoffRelocTable(ArrayList sections, - Map> relocationTable) { + private PECoffRelocTable createPECoffRelocTable(ArrayList sections, Map> relocationTable) { PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size()); /* - * For each of the symbols with associated relocation records, create a PECoff relocation - * entry. + * For each of the symbols with associated relocation records, create a PECoff relocation entry. */ for (Map.Entry> entry : relocationTable.entrySet()) { List relocs = entry.getValue(); @@ -315,18 +287,17 @@ return (pecoffRelocTable); } - private void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) { + private static void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) { RelocType relocType = reloc.getType(); int pecoffRelocType = getPECoffRelocationType(relocType); - PECoffSymbol sym = (PECoffSymbol)symbol.getNativeSymbol(); + PECoffSymbol sym = (PECoffSymbol) symbol.getNativeSymbol(); int symno = sym.getIndex(); int sectindex = reloc.getSection().getSectionId(); int offset = reloc.getOffset(); int addend = 0; switch (relocType) { - case FOREIGN_CALL_DIRECT: case JAVA_CALL_DIRECT: case STUB_CALL_DIRECT: case FOREIGN_CALL_INDIRECT_GOT: { @@ -336,47 +307,22 @@ offset = offset + reloc.getSize() + addend; break; } - case FOREIGN_CALL_DIRECT_FAR: { - // Create relocation entry - addend = -8; // Size in bytes of the patch location - // Relocation should be applied at the location after call operand - // 10 = 2 (jmp [r]) + 8 (imm64) - offset = offset + reloc.getSize() + addend - 2; - break; - } - case FOREIGN_CALL_INDIRECT: - case JAVA_CALL_INDIRECT: - case STUB_CALL_INDIRECT: { + case JAVA_CALL_INDIRECT: { // Do nothing. return; } - case EXTERNAL_DATA_REFERENCE_FAR: { - // Create relocation entry + case METASPACE_GOT_REFERENCE: + case EXTERNAL_PLT_TO_GOT: { addend = -4; // Size of 32-bit address of the GOT /* * Relocation should be applied before the test instruction to the move instruction. - * offset points to the test instruction after the instruction that loads - * the address of polling page. So set the offset appropriately. + * reloc.getOffset() points to the test instruction after the instruction that loads the address of + * polling page. So set the offset appropriately. */ offset = offset + addend; break; } - case METASPACE_GOT_REFERENCE: - case EXTERNAL_PLT_TO_GOT: - case STATIC_STUB_TO_STATIC_METHOD: - case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { - addend = -4; // Size of 32-bit address of the GOT - /* - * Relocation should be applied before the test instruction to - * the move instruction. reloc.getOffset() points to the - * test instruction after the instruction that loads the - * address of polling page. So set the offset appropriately. - */ - offset = offset + addend; - break; - } - case EXTERNAL_GOT_TO_PLT: - case LOADTIME_ADDRESS: { + case EXTERNAL_GOT_TO_PLT: { // this is load time relocations break; } @@ -391,27 +337,17 @@ int pecoffRelocType = 0; // R__NONE if #define'd to 0 for all values of ARCH switch (PECoffTargetInfo.getPECoffArch()) { case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: - if (relocType == RelocType.FOREIGN_CALL_DIRECT || - relocType == RelocType.JAVA_CALL_DIRECT || + if (relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; } else if (relocType == RelocType.STUB_CALL_DIRECT) { pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; - } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { - pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; - } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || - relocType == RelocType.JAVA_CALL_INDIRECT || - relocType == RelocType.STUB_CALL_INDIRECT) { + } else if (relocType == RelocType.JAVA_CALL_INDIRECT) { pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE; - } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { + } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || + relocType == RelocType.EXTERNAL_PLT_TO_GOT) { pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; - } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || - relocType == RelocType.EXTERNAL_PLT_TO_GOT || - relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || - relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { - pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; - } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || - relocType == RelocType.LOADTIME_ADDRESS) { + } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) { pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; } else { assert false : "Unhandled relocation type: " + relocType; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoff.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,17 +25,16 @@ /** * - * Support for the creation of Coff files. - * Current support is limited to 64 bit x86_64. + * Support for the creation of Coff files. Current support is limited to 64 bit x86_64. * */ -public class PECoff { - +final class PECoff { + //@formatter:off /** * IMAGE_FILE_HEADER structure defines */ - public enum IMAGE_FILE_HEADER { + enum IMAGE_FILE_HEADER { Machine( 0, 2), NumberOfSections( 2, 2), TimeDateStamp( 4, 4), @@ -44,15 +43,15 @@ SizeOfOptionalHeader(16, 2), Characteristics(18, 2); - public final int off; - public final int sz; + final int off; + final int sz; IMAGE_FILE_HEADER(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 20; + static int totalsize = 20; /** * IMAGE_FILE_HEADER defines @@ -61,15 +60,15 @@ /** * Machine */ - public static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0; - public static final char IMAGE_FILE_MACHINE_AMD64 = 0x8664; + static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0; + static final char IMAGE_FILE_MACHINE_AMD64 = 0x8664; } /** * IMAGE_SECTION_HEADER structure defines */ - public enum IMAGE_SECTION_HEADER { + enum IMAGE_SECTION_HEADER { Name( 0, 8), PhysicalAddress( 8, 4), VirtualSize( 8, 4), @@ -82,15 +81,15 @@ NumberOfLinenumbers(34, 2), Characteristics(36, 4); - public final int off; - public final int sz; + final int off; + final int sz; IMAGE_SECTION_HEADER(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 40; + static int totalsize = 40; /** * IMAGE_SECTION_HEADER defines @@ -99,29 +98,33 @@ /** * Characteristics */ - public static final int IMAGE_SCN_CNT_CODE = 0x20; - public static final int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40; - public static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80; - public static final int IMAGE_SCN_LNK_COMDAT = 0x1000; - public static final int IMAGE_SCN_LNK_INFO = 0x200; - public static final int IMAGE_SCN_LNK_REMOVE = 0x800; + static final int IMAGE_SCN_CNT_CODE = 0x20; + static final int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40; + static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80; + static final int IMAGE_SCN_LNK_COMDAT = 0x1000; + static final int IMAGE_SCN_LNK_INFO = 0x200; + static final int IMAGE_SCN_LNK_REMOVE = 0x800; - public static final int IMAGE_SCN_ALIGN_1BYTES = 0x100000; - public static final int IMAGE_SCN_ALIGN_2BYTES = 0x200000; - public static final int IMAGE_SCN_ALIGN_4BYTES = 0x300000; - public static final int IMAGE_SCN_ALIGN_8BYTES = 0x400000; - public static final int IMAGE_SCN_ALIGN_16BYTES = 0x500000; - public static final int IMAGE_SCN_ALIGN_32BYTES = 0x600000; - public static final int IMAGE_SCN_ALIGN_64BYTES = 0x700000; - public static final int IMAGE_SCN_ALIGN_MASK = 0xf00000; - public static final int IMAGE_SCN_ALIGN_SHIFT = 20; + static final int IMAGE_SCN_ALIGN_1BYTES = 0x100000; + static final int IMAGE_SCN_ALIGN_2BYTES = 0x200000; + static final int IMAGE_SCN_ALIGN_4BYTES = 0x300000; + static final int IMAGE_SCN_ALIGN_8BYTES = 0x400000; + static final int IMAGE_SCN_ALIGN_16BYTES = 0x500000; + static final int IMAGE_SCN_ALIGN_32BYTES = 0x600000; + static final int IMAGE_SCN_ALIGN_64BYTES = 0x700000; + static final int IMAGE_SCN_ALIGN_128BYTES = 0x800000; + static final int IMAGE_SCN_ALIGN_256BYTES = 0x900000; + static final int IMAGE_SCN_ALIGN_512BYTES = 0xa00000; + static final int IMAGE_SCN_ALIGN_1024BYTES = 0xb00000; + static final int IMAGE_SCN_ALIGN_MASK = 0xf00000; + static final int IMAGE_SCN_ALIGN_SHIFT = 20; - public static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; + static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; - public static final int IMAGE_SCN_MEM_SHARED = 0x10000000; - public static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000; - public static final int IMAGE_SCN_MEM_READ = 0x40000000; - public static final int IMAGE_SCN_MEM_WRITE = 0x80000000; + static final int IMAGE_SCN_MEM_SHARED = 0x10000000; + static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000; + static final int IMAGE_SCN_MEM_READ = 0x40000000; + static final int IMAGE_SCN_MEM_WRITE = 0x80000000; } @@ -130,7 +133,7 @@ * * IMAGE_SYMBOL structure defines */ - public enum IMAGE_SYMBOL { + enum IMAGE_SYMBOL { ShortName( 0, 8), Short( 0, 4), Long( 4, 4), @@ -140,63 +143,63 @@ StorageClass(16, 1), NumberOfAuxSymbols(17, 1); - public final int off; - public final int sz; + final int off; + final int sz; IMAGE_SYMBOL(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 18; + static int totalsize = 18; /** * Type */ - public static final int IMAGE_SYM_DTYPE_NONE = 0x0; - public static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20; + static final int IMAGE_SYM_DTYPE_NONE = 0x0; + static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20; /** * StorageClass */ - public static final int IMAGE_SYM_CLASS_NULL = 0x0; - public static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2; - public static final int IMAGE_SYM_CLASS_STATIC = 0x3; - public static final int IMAGE_SYM_CLASS_LABEL = 0x6; + static final int IMAGE_SYM_CLASS_NULL = 0x0; + static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2; + static final int IMAGE_SYM_CLASS_STATIC = 0x3; + static final int IMAGE_SYM_CLASS_LABEL = 0x6; } /** * IMAGE_RELOCATION structure defines */ - public enum IMAGE_RELOCATION { + enum IMAGE_RELOCATION { VirtualAddress( 0, 4), SymbolTableIndex( 4, 4), Type( 8, 2); - public final int off; - public final int sz; + final int off; + final int sz; IMAGE_RELOCATION(int offset, int size) { this.off = offset; this.sz = size; } - public static int totalsize = 10; + static int totalsize = 10; /** * Relocation types */ - public static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0; - public static final int IMAGE_REL_AMD64_ADDR32 = 0x2; - public static final int IMAGE_REL_AMD64_ADDR64 = 0x1; - public static final int IMAGE_REL_AMD64_REL32 = 0x4; - public static final int IMAGE_REL_AMD64_REL32_1 = 0x5; - public static final int IMAGE_REL_AMD64_REL32_2 = 0x6; - public static final int IMAGE_REL_AMD64_REL32_3 = 0x7; - public static final int IMAGE_REL_AMD64_REL32_4 = 0x8; - public static final int IMAGE_REL_AMD64_REL32_5 = 0x9; + static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0; + static final int IMAGE_REL_AMD64_ADDR32 = 0x2; + static final int IMAGE_REL_AMD64_ADDR64 = 0x1; + static final int IMAGE_REL_AMD64_REL32 = 0x4; + static final int IMAGE_REL_AMD64_REL32_1 = 0x5; + static final int IMAGE_REL_AMD64_REL32_2 = 0x6; + static final int IMAGE_REL_AMD64_REL32_3 = 0x7; + static final int IMAGE_REL_AMD64_REL32_4 = 0x8; + static final int IMAGE_REL_AMD64_REL32_5 = 0x9; } - + //@formatter:on } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffByteBuffer.java Tue Sep 05 10:09:44 2017 -0700 @@ -26,9 +26,9 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; -public class PECoffByteBuffer { +final class PECoffByteBuffer { - public static ByteBuffer allocate(int size) { + static ByteBuffer allocate(int size) { ByteBuffer buf = ByteBuffer.allocate(size); // Only support Little Endian on Windows buf.order(ByteOrder.LITTLE_ENDIAN); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffContainer.java Tue Sep 05 10:09:44 2017 -0700 @@ -26,14 +26,13 @@ import java.io.File; import java.io.FileOutputStream; -public class PECoffContainer { +final class PECoffContainer { - File outputFile; - FileOutputStream outputStream; - long fileOffset; + private final File outputFile; + private FileOutputStream outputStream; + private long fileOffset; - public PECoffContainer(String fileName, String aotVersion) { - String baseName; + PECoffContainer(String fileName) { outputFile = new File(fileName); if (outputFile.exists()) { @@ -48,7 +47,7 @@ fileOffset = 0; } - public void close() { + void close() { try { outputStream.close(); } catch (Exception e) { @@ -56,8 +55,10 @@ } } - public void writeBytes(byte [] bytes) { - if (bytes == null) return; + void writeBytes(byte[] bytes) { + if (bytes == null) { + return; + } try { outputStream.write(bytes); } catch (Exception e) { @@ -67,11 +68,13 @@ } // Write bytes to output file with up front alignment padding - public void writeBytes(byte [] bytes, int alignment) { - if (bytes == null) return; + void writeBytes(byte[] bytes, int alignment) { + if (bytes == null) { + return; + } try { // Pad to alignment - while ((fileOffset & (long)(alignment-1)) != 0) { + while ((fileOffset & (alignment - 1)) != 0) { outputStream.write(0); fileOffset++; } @@ -82,4 +85,3 @@ fileOffset += bytes.length; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffHeader.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,45 +24,41 @@ package jdk.tools.jaotc.binformat.pecoff; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER; -import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffHeader { - ByteBuffer header; +final class PECoffHeader { + private final ByteBuffer header; - public PECoffHeader() { + PECoffHeader() { header = PECoffByteBuffer.allocate(IMAGE_FILE_HEADER.totalsize); header.putChar(IMAGE_FILE_HEADER.Machine.off, IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64); - header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int)(System.currentTimeMillis()/1000)); + header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int) (System.currentTimeMillis() / 1000)); header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, 0); header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, 0); - header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char)0); - header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char)0); + header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char) 0); + header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char) 0); } // Update header with the number of total sections - public void setSectionCount(int count) { - header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char)count); + void setSectionCount(int count) { + header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char) count); } // Update header with the number of total symbols - public void setSymbolCount(int count) { + void setSymbolCount(int count) { header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, count); } // Update header with the offset of symbol table - public void setSymbolOff(int offset) { + void setSymbolOff(int offset) { header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, offset); } - public byte[] getArray() { + byte[] getArray() { return header.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocEntry.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,26 +24,23 @@ package jdk.tools.jaotc.binformat.pecoff; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffRelocEntry { - ByteBuffer entry; +final class PECoffRelocEntry { + private final ByteBuffer entry; - public PECoffRelocEntry(int offset, int symno, int type) { + PECoffRelocEntry(int offset, int symno, int type) { entry = PECoffByteBuffer.allocate(IMAGE_RELOCATION.totalsize); entry.putInt(IMAGE_RELOCATION.VirtualAddress.off, offset); entry.putInt(IMAGE_RELOCATION.SymbolTableIndex.off, symno); - entry.putChar(IMAGE_RELOCATION.Type.off, (char)type); + entry.putChar(IMAGE_RELOCATION.Type.off, (char) type); } - public byte[] getArray() { + byte[] getArray() { return entry.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffRelocTable.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,52 +25,47 @@ import java.util.ArrayList; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION; import jdk.tools.jaotc.binformat.pecoff.PECoffRelocEntry; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffRelocTable { +final class PECoffRelocTable { ArrayList> relocEntries; - public PECoffRelocTable(int numsects) { - relocEntries = new ArrayList>(numsects); - for (int i = 0; i < numsects; i++) + PECoffRelocTable(int numsects) { + relocEntries = new ArrayList<>(numsects); + for (int i = 0; i < numsects; i++) { relocEntries.add(new ArrayList()); + } } - public void createRelocationEntry(int sectindex, - int offset, - int symno, - int type) { - - PECoffRelocEntry entry = new PECoffRelocEntry(offset, - symno, - type); + void createRelocationEntry(int sectindex, int offset, int symno, int type) { + PECoffRelocEntry entry = new PECoffRelocEntry(offset, symno, type); relocEntries.get(sectindex).add(entry); } - public int getAlign() { return (4); } + static int getAlign() { + return (4); + } - public int getNumRelocs(int section_index) { + int getNumRelocs(int section_index) { return relocEntries.get(section_index).size(); } // Return the relocation entries for a single section - // or null if no entries added to section - public byte [] getRelocData(int section_index) { + // or null if no entries added to section + byte[] getRelocData(int section_index) { ArrayList entryList = relocEntries.get(section_index); int entryCount = entryList.size(); int allocCount = entryCount; - if (entryCount == 0) + if (entryCount == 0) { return null; - - if (entryCount > 0xFFFF) + } + if (entryCount > 0xFFFF) { allocCount++; - + } ByteBuffer relocData = PECoffByteBuffer.allocate(allocCount * IMAGE_RELOCATION.totalsize); // If number of relocs exceeds 65K, add the real size @@ -89,4 +84,3 @@ return (relocData.array()); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSection.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,32 +24,39 @@ package jdk.tools.jaotc.binformat.pecoff; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffSection { - ByteBuffer section; - byte [] data; - boolean hasrelocations; - int sectionIndex; - int align; +final class PECoffSection { + private final ByteBuffer section; + private final byte[] data; + private final boolean hasrelocations; + private final int sectionIndex; + private final int align; - public PECoffSection(String sectName, byte [] sectData, int sectFlags, - boolean hasRelocations, int sectIndex) { + PECoffSection(String sectName, byte[] sectData0, int sectFlags0, int sectAlign, boolean hasRelocations, int sectIndex) { section = PECoffByteBuffer.allocate(IMAGE_SECTION_HEADER.totalsize); - // bug: If JVM.oop.got section is empty, VM exits since JVM.oop.got - // symbol ends up as external forwarded reference. - if (sectData.length == 0) sectData = new byte[8]; + // If .oop.got section is empty, VM exits since .oop.got + // symbol ends up as external forwarded reference. + byte[] sectData = sectData0; + if (sectData0.length == 0) { + sectData = new byte[8]; + } // Copy only Max allowed bytes to Section Entry - byte [] Name = sectName.getBytes(); - int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ? - Name.length : IMAGE_SECTION_HEADER.Name.sz; + byte[] Name = sectName.getBytes(); + int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ? Name.length : IMAGE_SECTION_HEADER.Name.sz; + + assert !(sectAlign < 1 || sectAlign > 1024 || (sectAlign & (sectAlign - 1)) != 0) : "section alignment is not valid: " + sectAlign; + align = sectAlign; + + // Using 32 because IMAGE_SCN_ALIGN_*BYTES is value + 1 + int sectAlignBits = (32 - Integer.numberOfLeadingZeros(align)) << IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT; + // Clear and set alignment bits + int sectFlags = (sectFlags0 & ~IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) | (sectAlignBits & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK); section.put(Name, IMAGE_SECTION_HEADER.Name.off, max); @@ -57,84 +64,69 @@ section.putInt(IMAGE_SECTION_HEADER.VirtualAddress.off, 0); section.putInt(IMAGE_SECTION_HEADER.SizeOfRawData.off, sectData.length); section.putInt(IMAGE_SECTION_HEADER.PointerToLinenumbers.off, 0); - section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char)0); + section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char) 0); section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, sectFlags); - // Extract alignment from Characteristics field - int alignshift = (sectFlags & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) >> - IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT; - - // Use 8 byte alignment if not specified - if (alignshift == 0) - alignshift = 3; - else - --alignshift; - - align = 1 << alignshift; - data = sectData; hasrelocations = hasRelocations; sectionIndex = sectIndex; } - public long getSize() { + long getSize() { return section.getInt(IMAGE_SECTION_HEADER.SizeOfRawData.off); } - public int getDataAlign() { + int getDataAlign() { return (align); } // Alignment requirements for the IMAGE_SECTION_HEADER structures - public static int getShdrAlign() { + static int getShdrAlign() { return (4); } - public byte[] getArray() { + byte[] getArray() { return section.array(); } - public byte[] getDataArray() { + byte[] getDataArray() { return data; } - public void setOffset(long offset) { - section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int)offset); + void setOffset(long offset) { + section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int) offset); } - public long getOffset() { + long getOffset() { return (section.getInt(IMAGE_SECTION_HEADER.PointerToRawData.off)); } - public void setReloff(int offset) { + void setReloff(int offset) { section.putInt(IMAGE_SECTION_HEADER.PointerToRelocations.off, offset); } - public void setRelcount(int count) { + void setRelcount(int count) { // If the number of relocs is larger than 65K, then set - // the overflow bit. The real count will be written to + // the overflow bit. The real count will be written to // the first reloc entry for this section. if (count > 0xFFFF) { int flags; - section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)0xFFFF); + section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) 0xFFFF); flags = section.getInt(IMAGE_SECTION_HEADER.Characteristics.off); flags |= IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_NRELOC_OVFL; section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, flags); - } - else { - section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)count); + } else { + section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char) count); } } - public boolean hasRelocations() { + boolean hasRelocations() { return hasrelocations; } - public int getSectionId() { + int getSectionId() { return sectionIndex; } } - - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,18 +24,15 @@ package jdk.tools.jaotc.binformat.pecoff; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import jdk.tools.jaotc.binformat.NativeSymbol; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffSymbol extends NativeSymbol { - ByteBuffer sym; +final class PECoffSymbol extends NativeSymbol { + private final ByteBuffer sym; - public PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass, - byte sectindex, long offset, long size) { + PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass, byte sectindex, long offset) { super(symbolindex); sym = PECoffByteBuffer.allocate(IMAGE_SYMBOL.totalsize); @@ -43,19 +40,18 @@ sym.putInt(IMAGE_SYMBOL.Short.off, 0); sym.putInt(IMAGE_SYMBOL.Long.off, strindex); - sym.putInt(IMAGE_SYMBOL.Value.off, (int)offset); + sym.putInt(IMAGE_SYMBOL.Value.off, (int) offset); // Section indexes start at 1 but we manage the index internally // as 0 relative except in this structure - sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char)(sectindex+1)); + sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char) (sectindex + 1)); - sym.putChar(IMAGE_SYMBOL.Type.off, (char)type); + sym.putChar(IMAGE_SYMBOL.Type.off, (char) type); sym.put(IMAGE_SYMBOL.StorageClass.off, storageclass); - sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte)0); + sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte) 0); } - public byte[] getArray() { + byte[] getArray() { return sym.array(); } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffSymtab.java Tue Sep 05 10:09:44 2017 -0700 @@ -27,36 +27,35 @@ import java.nio.ByteOrder; import java.util.ArrayList; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL; import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol; import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer; -public class PECoffSymtab { - ArrayListsymbols = new ArrayList(); +final class PECoffSymtab { + ArrayList symbols = new ArrayList<>(); /** * number of symbols added */ - int symbolCount; + private int symbolCount; /** * String holding symbol table strings */ - private StringBuilder strTabContent; + private final StringBuilder strTabContent; /** - * Keeps track of bytes in string table since strTabContent.length() - * is number of chars, not bytes. + * Keeps track of bytes in string table since strTabContent.length() is number of chars, not + * bytes. */ private int strTabNrOfBytes; /** * String holding Linker Directives */ - private StringBuilder directives; + private final StringBuilder directives; - public PECoffSymtab() { + PECoffSymtab() { symbolCount = 0; strTabContent = new StringBuilder(); directives = new StringBuilder(); @@ -72,8 +71,7 @@ directives.append(" "); } - public PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass, - byte secHdrIndex, long offset, long size) { + PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass, byte secHdrIndex, long offset) { // Get the current symbol index and append symbol name to string table. int index; PECoffSymbol sym; @@ -82,7 +80,7 @@ index = 0; strTabContent.append('\0'); strTabNrOfBytes += 1; - sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size); + sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset); symbols.add(sym); } else { int nameSize = name.getBytes().length; @@ -94,10 +92,11 @@ strTabContent.append(name).append('\0'); strTabNrOfBytes += (nameSize + 1); - sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size); + sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset); symbols.add(sym); - if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL) + if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL) { addDirective(name, type); + } } symbolCount++; return (sym); @@ -105,37 +104,37 @@ private void addDirective(String name, byte type) { directives.append("/EXPORT:" + name); - if(type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) { + if (type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) { directives.append(",DATA"); } directives.append(" "); } - public int getSymtabCount() { + int getSymtabCount() { return symbolCount; } - public int getStrtabSize() { + int getStrtabSize() { return strTabNrOfBytes; } // Return a byte array that contains the symbol table entries - public byte[] getSymtabArray() { - ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount*IMAGE_SYMBOL.totalsize); + byte[] getSymtabArray() { + ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount * IMAGE_SYMBOL.totalsize); symtabData.order(ByteOrder.LITTLE_ENDIAN); // copy all symbols - for (int i = 0; i < symbolCount; i++ ) { + for (int i = 0; i < symbolCount; i++) { PECoffSymbol sym = symbols.get(i); - byte [] arr = sym.getArray(); + byte[] arr = sym.getArray(); symtabData.put(arr); } return (symtabData.array()); } // Return the string table array - public byte[] getStrtabArray() { - byte [] strs = strTabContent.toString().getBytes(); + byte[] getStrtabArray() { + byte[] strs = strTabContent.toString().getBytes(); // Update the size of the string table ByteBuffer buff = ByteBuffer.wrap(strs); @@ -145,7 +144,7 @@ return (strs); } - public byte[] getDirectiveArray() { + byte[] getDirectiveArray() { return (directives.toString().getBytes()); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/pecoff/PECoffTargetInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,14 +24,13 @@ package jdk.tools.jaotc.binformat.pecoff; import java.nio.ByteOrder; -import jdk.tools.jaotc.binformat.pecoff.PECoff; import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER; /** * Class that abstracts MACH-O target details. * */ -public class PECoffTargetInfo { +final class PECoffTargetInfo { /** * Target architecture. */ @@ -63,12 +62,11 @@ } } - public static char getPECoffArch() { + static char getPECoffArch() { return arch; } - public static String getOsName() { + static String getOsName() { return osName; } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -52,7 +52,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.TriState; -public class AOTBackend { +final class AOTBackend { private final Main main; private final OptionValues graalOptions; private final HotSpotBackend backend; @@ -60,28 +60,26 @@ private final HotSpotCodeCacheProvider codeCache; private final PhaseSuite graphBuilderSuite; private final HighTierContext highTierContext; - private final GraalFilters filters; - public AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, GraalFilters filters) { + AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend) { this.main = main; this.graalOptions = graalOptions; this.backend = backend; - this.filters = filters; providers = backend.getProviders(); codeCache = providers.getCodeCache(); graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions); highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL); } - public PhaseSuite getGraphBuilderSuite() { + PhaseSuite getGraphBuilderSuite() { return graphBuilderSuite; } - public HotSpotBackend getBackend() { + HotSpotBackend getBackend() { return backend; } - public HotSpotProviders getProviders() { + HotSpotProviders getProviders() { return providers; } @@ -96,7 +94,7 @@ } @SuppressWarnings("try") - public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod, DebugContext debug) { + CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod, DebugContext debug) { StructuredGraph graph = buildStructuredGraph(resolvedMethod, debug); if (graph != null) { return compileGraph(resolvedMethod, graph, debug); @@ -118,7 +116,7 @@ graphBuilderSuite.apply(graph, highTierContext); return graph; } catch (Throwable e) { - handleError(javaMethod, e, " (building graph)"); + main.handleError(javaMethod, e, " (building graph)"); } return null; } @@ -135,20 +133,11 @@ compilationResult, CompilationResultBuilderFactory.Default); } catch (Throwable e) { - handleError(resolvedMethod, e, " (compiling graph)"); + main.handleError(resolvedMethod, e, " (compiling graph)"); } return null; } - /** - * Returns whether the VM is a debug build. - * - * @return true is debug VM, false otherwise - */ - public boolean isDebugVM() { - return backend.getRuntime().getVMConfig().cAssertions; - } - private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) { PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); @@ -165,39 +154,12 @@ return graphBuilderSuite; } - private void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) { - String methodName = MiscUtils.uniqueMethodName(resolvedMethod); - - if (main.options.debug) { - main.printError("Failed compilation: " + methodName + ": " + e); - } - - // Ignore some exceptions when meta-compiling Graal. - if (filters.shouldIgnoreException(e)) { - return; - } - - Main.writeLog("Failed compilation of method " + methodName + message); - - if (!main.options.debug) { - main.printError("Failed compilation: " + methodName + ": " + e); - } - - if (main.options.verbose) { - e.printStackTrace(main.log); - } - - if (main.options.exitOnError) { - System.exit(1); - } - } - - public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) { + void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) { // This is really not installing the method. InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult), null, null); String disassembly = codeCache.disassemble(installedCode); if (disassembly != null) { - main.printlnDebug(disassembly); + main.printer.printlnDebug(disassembly); } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java Tue Sep 05 10:09:44 2017 -0700 @@ -48,7 +48,7 @@ * compilation of classes. It also defines methods that parse compilation result of Graal to create * target-independent representation {@code BinaryContainer} of the intended target binary. */ -public class AOTCompilationTask implements Runnable, Comparable { +final class AOTCompilationTask implements Runnable, Comparable { private static final AtomicInteger ids = new AtomicInteger(); @@ -77,7 +77,7 @@ */ private CompiledMethodInfo result; - public AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) { + AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) { this.main = main; this.graalOptions = graalOptions; this.id = ids.incrementAndGet(); @@ -95,7 +95,7 @@ // may include processing command line options used by the latter. HotSpotJVMCIRuntime.runtime(); - AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling"); + AOTCompiler.logCompilation(JavaMethodInfo.uniqueMethodName(method), "Compiling"); final long threadId = Thread.currentThread().getId(); @@ -137,7 +137,7 @@ } // For now precision to the nearest second is sufficient. - Main.writeLog(" Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs"); + LogPrinter.writeLog(" Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs"); if (main.options.debug) { aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult); } @@ -146,7 +146,7 @@ } private String getMethodDescription() { - return String.format("%-6d aot %s %s", getId(), MiscUtils.uniqueMethodName(method), + return String.format("%-6d aot %s %s", getId(), JavaMethodInfo.uniqueMethodName(method), getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") "); } @@ -154,11 +154,11 @@ return id; } - public int getEntryBCI() { + private static int getEntryBCI() { return JVMCICompiler.INVOCATION_ENTRY_BCI; } - public ResolvedJavaMethod getMethod() { + ResolvedJavaMethod getMethod() { return method; } @@ -167,7 +167,7 @@ * * @return the holder of this method */ - public AOTCompiledClass getHolder() { + AOTCompiledClass getHolder() { return holder; } @@ -176,7 +176,7 @@ * * @return result of this compilation task */ - public CompiledMethodInfo getResult() { + CompiledMethodInfo getResult() { return result; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -41,16 +41,16 @@ * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods * of a class {@code className} are maintained in an array list. */ -public class AOTCompiledClass { +final class AOTCompiledClass { - public static class AOTKlassData { - int gotIndex; // Index (offset/8) to the got in the .metaspace.got section - int classId; // Unique ID + static class AOTKlassData { + private int gotIndex; // Index (offset/8) to the got in the .metaspace.got section + private int classId; // Unique ID // Offset to compiled methods data in the .methods.offsets section. - int compiledMethodsOffset; + private int compiledMethodsOffset; // Offset to dependent methods data. - int dependentMethodsOffset; - long fingerprint; // Class fingerprint + private int dependentMethodsOffset; + private long fingerprint; // Class fingerprint private final String name; private boolean isArray; @@ -60,25 +60,25 @@ */ private ArrayList dependentMethods; - public AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) { + AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) { this.dependentMethods = new ArrayList<>(); this.classId = classId; this.fingerprint = fingerprint; - this.gotIndex = binaryContainer.addTwoSlotMetaspaceSymbol(name); + this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(name); this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods. this.dependentMethodsOffset = -1; this.name = name; this.isArray = name.length() > 0 && name.charAt(0) == '['; } - public long getFingerprint() { + long getFingerprint() { return fingerprint; } /** * Add a method to the list of dependent methods. */ - public synchronized boolean addDependentMethod(CompiledMethodInfo cm) { + synchronized boolean addDependentMethod(CompiledMethodInfo cm) { return dependentMethods.add(cm); } @@ -87,7 +87,7 @@ * * @return array list of dependent methods */ - public ArrayList getDependentMethods() { + ArrayList getDependentMethods() { return dependentMethods; } @@ -96,11 +96,11 @@ * * @return true if dependent methods exist, false otherwise */ - public boolean hasDependentMethods() { + boolean hasDependentMethods() { return !dependentMethods.isEmpty(); } - public void setCompiledMethodsOffset(int offset) { + void setCompiledMethodsOffset(int offset) { compiledMethodsOffset = offset; } @@ -108,7 +108,7 @@ int cntDepMethods = dependentMethods.size(); // Create array of dependent methods IDs. First word is count. ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer(); - this.dependentMethodsOffset = binaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer); + this.dependentMethodsOffset = BinaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer); for (CompiledMethodInfo methodInfo : dependentMethods) { dependenciesContainer.appendInt(methodInfo.getCodeId()); } @@ -176,7 +176,7 @@ * * @param compiledMethods AOT compiled methods */ - public AOTCompiledClass(ArrayList compiledMethods) { + AOTCompiledClass(ArrayList compiledMethods) { this.resolvedJavaType = null; this.compiledMethods = compiledMethods; this.representsStubs = true; @@ -185,7 +185,7 @@ /** * Construct an object with compiled versions of the named class. */ - public AOTCompiledClass(ResolvedJavaType resolvedJavaType) { + AOTCompiledClass(ResolvedJavaType resolvedJavaType) { this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType; this.compiledMethods = new ArrayList<>(); this.representsStubs = false; @@ -194,14 +194,14 @@ /** * @return the ResolvedJavaType of this class */ - public ResolvedJavaType getResolvedJavaType() { + ResolvedJavaType getResolvedJavaType() { return resolvedJavaType; } /** * Get the list of methods which should be compiled. */ - public ArrayList getMethods() { + ArrayList getMethods() { ArrayList m = methods; methods = null; // Free - it is not used after that. return m; @@ -210,7 +210,7 @@ /** * Get the number of all AOT classes. */ - public static int getClassesCount() { + static int getClassesCount() { return classesCount; } @@ -219,14 +219,14 @@ * * @return number of methods which should be compiled */ - public int getMethodCount() { + int getMethodCount() { return methods.size(); } /** * Add a method to the list of methods to be compiled. */ - public void addMethod(ResolvedJavaMethod method) { + void addMethod(ResolvedJavaMethod method) { methods.add(method); } @@ -235,14 +235,14 @@ * * @return true if this class contains methods which should be compiled, false otherwise */ - public boolean hasMethods() { + boolean hasMethods() { return !methods.isEmpty(); } /** * Add a method to the list of compiled methods. This method needs to be thread-safe. */ - public synchronized boolean addCompiledMethod(CompiledMethodInfo cm) { + synchronized boolean addCompiledMethod(CompiledMethodInfo cm) { return compiledMethods.add(cm); } @@ -251,7 +251,7 @@ * * @return array list of compiled methods */ - public ArrayList getCompiledMethods() { + ArrayList getCompiledMethods() { return compiledMethods; } @@ -260,14 +260,14 @@ * * @return true if methods were compiled, false otherwise */ - public boolean hasCompiledMethods() { + boolean hasCompiledMethods() { return !compiledMethods.isEmpty(); } /** * Add a klass data. */ - public synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { + synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { String name = type.getName(); long fingerprint = type.getFingerprint(); AOTKlassData data = klassData.get(name); @@ -280,15 +280,15 @@ return data; } - public synchronized static AOTKlassData getAOTKlassData(String name) { + synchronized static AOTKlassData getAOTKlassData(String name) { return klassData.get(name); } - public synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) { + synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) { return getAOTKlassData(type.getName()); } - public void addAOTKlassData(BinaryContainer binaryContainer) { + void addAOTKlassData(BinaryContainer binaryContainer) { for (CompiledMethodInfo methodInfo : compiledMethods) { // Record methods holder methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); @@ -309,7 +309,7 @@ } } - public synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { + synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { if (type.isArray()) { return addAOTKlassData(binaryContainer, type); } @@ -317,14 +317,15 @@ AOTKlassData old = getAOTKlassData(type); if (old != null) { boolean assertsEnabled = false; + // Next assignment will be executed when asserts are enabled. assert assertsEnabled = true; if (assertsEnabled) { HotSpotResolvedObjectType s = type.getSuperclass(); if (s != null) { - assert getAOTKlassData(s) != null : "fingerprint super " + s.getName() + " needed for " + type.getName(); + assert getAOTKlassData(s) != null : "fingerprint for super " + s.getName() + " needed for " + type.getName(); } for (HotSpotResolvedObjectType i : type.getInterfaces()) { - assert getAOTKlassData(i) != null : "fingerprint super " + i.getName() + " needed for " + type.getName(); + assert getAOTKlassData(i) != null : "fingerprint for interface " + i.getName() + " needed for " + type.getName(); } } return old; @@ -345,10 +346,10 @@ /* * Put methods data to contained. */ - public void putMethodsData(BinaryContainer binaryContainer) { + void putMethodsData(BinaryContainer binaryContainer) { ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer(); int cntMethods = compiledMethods.size(); - int startMethods = binaryContainer.addMethodsCount(cntMethods, container); + int startMethods = BinaryContainer.addMethodsCount(cntMethods, container); for (CompiledMethodInfo methodInfo : compiledMethods) { methodInfo.addMethodOffsets(binaryContainer, container); } @@ -361,18 +362,18 @@ data.setCompiledMethodsOffset(startMethods); } - public static void putAOTKlassData(BinaryContainer binaryContainer) { + static void putAOTKlassData(BinaryContainer binaryContainer) { ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer(); for (AOTKlassData data : klassData.values()) { data.putAOTKlassData(binaryContainer, container); } } - public boolean representsStubs() { + boolean representsStubs() { return representsStubs; } - public void clear() { + void clear() { for (CompiledMethodInfo c : compiledMethods) { c.clear(); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiler.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -35,7 +35,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; -public class AOTCompiler { +final class AOTCompiler { private final Main main; @@ -68,7 +68,7 @@ /** * Create a compile queue with the given number of threads. */ - public CompileQueue(final int threads) { + CompileQueue(final int threads) { super(threads, threads, 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>()); startTime = System.currentTimeMillis(); } @@ -79,7 +79,7 @@ if (task.getResult() != null) { final int count = successfulMethodCount.incrementAndGet(); if (count % 100 == 0) { - main.printInfo("."); + main.printer.printInfo("."); } CompiledMethodInfo result = task.getResult(); if (result != null) { @@ -87,9 +87,9 @@ } } else { failedMethodCount.incrementAndGet(); - main.printlnVerbose(""); + main.printer.printlnVerbose(""); ResolvedJavaMethod method = task.getMethod(); - main.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor()); + main.printer.printlnVerbose(" failed " + method.getName() + method.getSignature().toMethodDescriptor()); } } @@ -98,8 +98,8 @@ final long endTime = System.currentTimeMillis(); final int success = successfulMethodCount.get(); final int failed = failedMethodCount.get(); - main.printlnInfo(""); - main.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)"); + main.printer.printlnInfo(""); + main.printer.printlnInfo(success + " methods compiled, " + failed + " methods failed (" + (endTime - startTime) + " ms)"); } } @@ -110,7 +110,7 @@ * @param aotBackend * @param threads number of compilation threads */ - public AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) { + AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) { this.main = main; this.graalOptions = graalOptions; this.compileQueue = new CompileQueue(threads); @@ -123,9 +123,9 @@ * @param classes a list of class to compile * @throws InterruptedException */ - public List compileClasses(List classes) throws InterruptedException { - main.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads"); - main.printInfo("."); // Compilation progress indication. + List compileClasses(List classes) throws InterruptedException { + main.printer.printlnInfo("Compiling with " + compileQueue.getCorePoolSize() + " threads"); + main.printer.printInfo("."); // Compilation progress indication. for (AOTCompiledClass c : classes) { for (ResolvedJavaMethod m : c.getMethods()) { @@ -160,8 +160,8 @@ } } - public static void logCompilation(String methodName, String message) { - Main.writeLog(message + " " + methodName); + static void logCompilation(String methodName, String message) { + LogPrinter.writeLog(message + " " + methodName); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -29,18 +29,18 @@ import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo { +final class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo { private final HotSpotResolvedJavaMethod method; private final Backend backend; - public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) { + AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) { this.method = method; this.backend = backend; } public String getSymbolName() { - return MiscUtils.uniqueMethodName(method); + return JavaMethodInfo.uniqueMethodName(method); } public String getNameAndSignature() { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -30,12 +30,12 @@ import jdk.vm.ci.hotspot.HotSpotCompiledCode; -public class AOTStub implements JavaMethodInfo { +final class AOTStub implements JavaMethodInfo { private final Stub stub; private final Backend backend; - public AOTStub(Stub stub, Backend backend) { + AOTStub(Stub stub, Backend backend) { this.stub = stub; this.backend = backend; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, 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. + */ + +package jdk.tools.jaotc; + +import org.graalvm.compiler.bytecode.Bytecodes; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +final class CallInfo { + + static boolean isStaticCall(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC); + } + return false; + } + + static boolean isSpecialCall(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL); + } + return false; + } + + private static boolean isInvokeVirtual(Call call) { + if (isJavaCall(call)) { + return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE); + } + return false; + } + + static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) { + return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL); + } + + static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) { + return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL); + } + + private static boolean isJavaCall(Call call) { + // If there is no associated debug info return false + if (call.debugInfo == null) { + return false; + } + BytecodePosition bcpos = call.debugInfo.getBytecodePosition(); + ResolvedJavaMethod method = bcpos.getMethod(); + // If bytecode position indicates a special value (negative value) it is + // not a normal java call + if (bcpos.getBCI() < 0) { + return false; + } + // If there is no method associated with the debuginfo, return false + if (method == null) { + return false; + } + assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call"; + return true; + } + + private static byte getByteCode(Call call) { + ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod(); + int callPosition = call.debugInfo.getBytecodePosition().getBCI(); + byte[] code = m.getCode(); + return code[callPosition]; + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -31,10 +31,10 @@ */ abstract class CallSiteRelocationInfo { - public final String targetSymbol; - public final RelocType type; + final String targetSymbol; + final RelocType type; - public CallSiteRelocationInfo(String targetSymbol, RelocType type) { + CallSiteRelocationInfo(String targetSymbol, RelocType type) { this.targetSymbol = targetSymbol; this.type = type; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -37,9 +37,9 @@ */ abstract class CallSiteRelocationSymbol { - public final Symbol symbol; + final Symbol symbol; - public CallSiteRelocationSymbol(Symbol symbol) { + CallSiteRelocationSymbol(Symbol symbol) { assert symbol != null; this.symbol = symbol; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeOffsets.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -27,7 +27,7 @@ import jdk.vm.ci.code.site.Mark; -public final class CodeOffsets { +final class CodeOffsets { private final int entry; private final int verifiedEntry; private final int exceptionHandler; @@ -40,7 +40,7 @@ this.deoptHandler = deoptHandler; } - public static CodeOffsets buildFrom(List marks) { + static CodeOffsets buildFrom(List marks) { int entry = 0; int verifiedEntry = 0; int exceptionHandler = -1; @@ -73,19 +73,19 @@ return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler); } - public int entry() { + int entry() { return entry; } - public int verifiedEntry() { + int verifiedEntry() { return verifiedEntry; } - public int exceptionHandler() { + int exceptionHandler() { return exceptionHandler; } - public int deoptHandler() { + int deoptHandler() { return deoptHandler; } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CodeSectionProcessor.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -28,7 +28,7 @@ import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.CodeContainer; import jdk.tools.jaotc.binformat.Symbol; -import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.StubInformation; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; @@ -38,7 +38,7 @@ import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.meta.ResolvedJavaMethod; -class CodeSectionProcessor { +final class CodeSectionProcessor { private final TargetDescription target; @@ -89,11 +89,11 @@ // Align and pad method entry CodeContainer codeSection = binaryContainer.getCodeContainer(); - int codeIdOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize()); + int codeIdOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeSegmentSize()); // Store CodeId into code. It will be use by find_aot() using code.segments methodInfo.setCodeId(); binaryContainer.appendIntToCode(methodInfo.getCodeId()); - int textBaseOffset = binaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment()); + int textBaseOffset = BinaryContainer.alignUp(codeSection, binaryContainer.getCodeEntryAlignment()); codeSection.createSymbol(textBaseOffset, Symbol.Kind.JAVA_FUNCTION, Symbol.Binding.LOCAL, targetCodeSize, entry); @@ -102,7 +102,7 @@ // Write code bytes of the current method into byte stream binaryContainer.appendCodeBytes(targetCode, 0, targetCodeSize); - int currentStubOffset = binaryContainer.alignUp(codeSection, 8); + int currentStubOffset = BinaryContainer.alignUp(codeSection, 8); // Set the offset at which stubs of this method would be laid out methodInfo.setStubsOffset(currentStubOffset - textBaseOffset); // step through all calls, for every call, add a stub @@ -111,10 +111,10 @@ final Call callInfopoint = (Call) infopoint; if (callInfopoint.target instanceof ResolvedJavaMethod) { ResolvedJavaMethod call = (ResolvedJavaMethod) callInfopoint.target; - StubInformation stub = addCallStub(MiscUtils.isVirtualCall(methodInfo, callInfopoint)); + StubInformation stub = addCallStub(CallInfo.isVirtualCall(methodInfo, callInfopoint)); // Get the targetSymbol. A symbol for this will be created later during plt // creation - String targetSymbol = MiscUtils.uniqueMethodName(call) + ".at." + infopoint.pcOffset; + String targetSymbol = JavaMethodInfo.uniqueMethodName(call) + ".at." + infopoint.pcOffset; methodInfo.addStubCode(targetSymbol, stub); currentStubOffset += stub.getSize(); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Collector.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,218 @@ +/* + * 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. + */ + +package jdk.tools.jaotc; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.tools.jaotc.collect.ClassSearch; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +final class Collector { + + private final Main main; + + Collector(Main main) { + this.main = main; + } + + Set> collectClassesToCompile() { + Set> classesToCompile = new HashSet<>(); + FileSupport fileSupport = new FileSupport(); + ClassSearch lookup = new ClassSearch(); + lookup.addProvider(new ModuleSourceProvider()); + lookup.addProvider(new ClassNameSourceProvider(fileSupport)); + lookup.addProvider(new JarSourceProvider()); + lookup.addProvider(new DirectorySourceProvider(fileSupport)); + + List foundClasses = null; + try { + foundClasses = lookup.search(main.options.files, main.options.searchPath); + } catch (InternalError e) { + main.printer.reportError(e); + return null; + } + + for (LoadedClass loadedClass : foundClasses) { + classesToCompile.add(loadedClass.getLoadedClass()); + } + return classesToCompile; + } + + private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions) { + for (ResolvedJavaMethod m : methods) { + addMethod(aotClass, m, compilationRestrictions); + } + } + + private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions) { + // Don't compile native or abstract methods. + if (!method.hasBytecodes()) { + return; + } + if (!compilationRestrictions.shouldCompileMethod(method)) { + return; + } + if (!main.filters.shouldCompileMethod(method)) { + return; + } + + aotClass.addMethod(method); + main.printer.printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor()); + } + + /** + * Collect all method we should compile. + * + * @return array list of AOT classes which have compiled methods. + */ + List collectMethodsToCompile(Set> classesToCompile, MetaAccessProvider metaAccess) { + int total = 0; + int count = 0; + List classes = new ArrayList<>(); + CompilationSpec compilationRestrictions = collectSpecifiedMethods(); + + for (Class c : classesToCompile) { + ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c); + if (main.filters.shouldCompileAnyMethodInClass(resolvedJavaType)) { + AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType); + main.printer.printlnVerbose(" Scanning " + c.getName()); + + // Constructors + try { + ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors(); + addMethods(aotClass, ctors, compilationRestrictions); + total += ctors.length; + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (main.options.ignoreClassLoadingErrors) { + main.printer.printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Methods + try { + ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods(); + addMethods(aotClass, methods, compilationRestrictions); + total += methods.length; + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (main.options.ignoreClassLoadingErrors) { + main.printer.printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Class initializer + try { + ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer(); + if (clinit != null) { + addMethod(aotClass, clinit, compilationRestrictions); + total++; + } + } catch (Throwable e) { + // If we are running in JCK mode we ignore all exceptions. + if (main.options.ignoreClassLoadingErrors) { + main.printer.printError(c.getName() + ": " + e); + } else { + throw new InternalError(e); + } + } + + // Found any methods to compile? Add the class. + if (aotClass.hasMethods()) { + classes.add(aotClass); + count += aotClass.getMethodCount(); + } + } + } + main.printer.printInfo(total + " methods total, " + count + " methods to compile"); + return classes; + } + + /** + * If a file with compilation limitations is specified using flag --compile-commands, read the + * file's contents and collect the restrictions. + */ + private CompilationSpec collectSpecifiedMethods() { + CompilationSpec compilationRestrictions = new CompilationSpec(); + String methodListFileName = main.options.methodList; + + if (methodListFileName != null && !methodListFileName.equals("")) { + try { + FileReader methListFile = new FileReader(methodListFileName); + BufferedReader readBuf = new BufferedReader(methListFile); + String line = null; + while ((line = readBuf.readLine()) != null) { + String trimmedLine = line.trim(); + if (!trimmedLine.startsWith("#")) { + String[] components = trimmedLine.split(" "); + if (components.length == 2) { + String directive = components[0]; + String pattern = components[1]; + switch (directive) { + case "compileOnly": + compilationRestrictions.addCompileOnlyPattern(pattern); + break; + case "exclude": + compilationRestrictions.addExcludePattern(pattern); + break; + default: + System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName); + } + } else { + if (!trimmedLine.equals("")) { + System.out.println("Ignoring malformed line:\n\t " + line + "\n"); + } + } + } + } + readBuf.close(); + } catch (FileNotFoundException e) { + throw new InternalError("Unable to open method list file: " + methodListFileName, e); + } catch (IOException e) { + throw new InternalError("Unable to read method list file: " + methodListFileName, e); + } + } + + return compilationRestrictions; + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompilationSpec.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -32,7 +32,7 @@ /** * A class encapsulating any user-specified compilation restrictions. */ -public class CompilationSpec { +final class CompilationSpec { /** * Set of method names to restrict compilation to. @@ -51,7 +51,7 @@ * * @param pattern regex or non-regex pattern string */ - public void addCompileOnlyPattern(String pattern) { + void addCompileOnlyPattern(String pattern) { if (pattern.contains("*")) { compileOnlyPatterns.add(Pattern.compile(pattern)); } else { @@ -64,7 +64,7 @@ * * @param pattern regex or non-regex pattern string */ - public void addExcludePattern(String pattern) { + void addExcludePattern(String pattern) { if (pattern.contains("*")) { excludePatterns.add(Pattern.compile(pattern)); } else { @@ -78,14 +78,14 @@ * @param method method to be checked * @return true or false */ - public boolean shouldCompileMethod(ResolvedJavaMethod method) { + boolean shouldCompileMethod(ResolvedJavaMethod method) { if (compileWithRestrictions()) { // If there are user-specified compileOnly patterns, default action // is not to compile the method. boolean compileMethod = compileOnlyStrings.isEmpty() && compileOnlyPatterns.isEmpty(); // Check if the method matches with any of the specified compileOnly patterns. - String methodName = MiscUtils.uniqueMethodName(method); + String methodName = JavaMethodInfo.uniqueMethodName(method); // compileOnly if (!compileMethod) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CompiledMethodInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -37,104 +37,7 @@ import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -public class CompiledMethodInfo { - - public static class StubInformation { - int stubOffset; // the offset inside the code (text + stubOffset) - int stubSize; // the stub size - int dispatchJumpOffset; // offset after main dispatch jump instruction - int resolveJumpOffset; // offset after jump instruction to runtime call resolution - // function. - int resolveJumpStart; // offset of jump instruction to VM runtime call resolution - // function. - int c2iJumpOffset; // offset after jump instruction to c2i adapter for static calls. - int movOffset; // offset after move instruction which loads from got cell: - // - Method* for static call - // - Klass* for virtual call - - boolean isVirtual; // virtual call stub - - // maybe add type of stub as well, right now we only have static stubs - - public StubInformation(int stubOffset, boolean isVirtual) { - this.stubOffset = stubOffset; - this.isVirtual = isVirtual; - this.stubSize = -1; - this.movOffset = -1; - this.c2iJumpOffset = -1; - this.resolveJumpOffset = -1; - this.resolveJumpStart = -1; - this.dispatchJumpOffset = -1; - } - - public int getOffset() { - return stubOffset; - } - - public boolean isVirtual() { - return isVirtual; - } - - public void setSize(int stubSize) { - this.stubSize = stubSize; - } - - public int getSize() { - return stubSize; - } - - public void setMovOffset(int movOffset) { - this.movOffset = movOffset + stubOffset; - } - - public int getMovOffset() { - return movOffset; - } - - public void setC2IJumpOffset(int c2iJumpOffset) { - this.c2iJumpOffset = c2iJumpOffset + stubOffset; - } - - public int getC2IJumpOffset() { - return c2iJumpOffset; - } - - public void setResolveJumpOffset(int resolveJumpOffset) { - this.resolveJumpOffset = resolveJumpOffset + stubOffset; - } - - public int getResolveJumpOffset() { - return resolveJumpOffset; - } - - public void setResolveJumpStart(int resolveJumpStart) { - this.resolveJumpStart = resolveJumpStart + stubOffset; - } - - public int getResolveJumpStart() { - return resolveJumpStart; - } - - public void setDispatchJumpOffset(int dispatchJumpOffset) { - this.dispatchJumpOffset = dispatchJumpOffset + stubOffset; - } - - public int getDispatchJumpOffset() { - return dispatchJumpOffset; - } - - public void verify() { - assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset; - assert stubSize > 0 : "incorrect stubSize: " + stubSize; - assert movOffset > 0 : "incorrect movOffset: " + movOffset; - assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset; - assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart; - assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset; - if (!isVirtual) { - assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset; - } - } - } +final class CompiledMethodInfo { private static final int UNINITIALIZED_OFFSET = -1; @@ -169,7 +72,7 @@ */ private int codeId; - public AOTMethodOffsets() { + AOTMethodOffsets() { this.nameOffset = UNINITIALIZED_OFFSET; this.textSectionOffset = UNINITIALIZED_OFFSET; this.metadataOffset = UNINITIALIZED_OFFSET; @@ -178,7 +81,7 @@ this.codeId = -1; } - protected void addMethodOffsets(ReadOnlyDataContainer container, String name) { + void addMethodOffsets(ReadOnlyDataContainer container, String name) { verify(name); // @formatter:off /* @@ -291,7 +194,7 @@ */ private static final AtomicInteger methodsCount = new AtomicInteger(); - public CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { + CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { this.name = methodInfo.getNameAndSignature(); this.compilationResult = compilationResult; this.methodInfo = methodInfo; @@ -299,11 +202,11 @@ this.methodOffsets = new AOTMethodOffsets(); } - public String name() { + String name() { return name; } - public void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { + void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); this.methodOffsets.addMethodOffsets(container, name); for (AOTKlassData data : dependentKlasses.values()) { @@ -311,15 +214,15 @@ } } - public CompilationResult getCompilationResult() { + CompilationResult getCompilationResult() { return compilationResult; } - public JavaMethodInfo getMethodInfo() { + JavaMethodInfo getMethodInfo() { return methodInfo; } - public void setTextSectionOffset(int textSectionOffset) { + void setTextSectionOffset(int textSectionOffset) { methodOffsets.setTextSectionOffset(textSectionOffset); } @@ -327,66 +230,66 @@ return methodOffsets.getTextSectionOffset(); } - public void setCodeId() { + void setCodeId() { methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId()); } - public int getCodeId() { + int getCodeId() { return this.methodOffsets.getCodeId(); } - public static int getMethodsCount() { + static int getMethodsCount() { return methodsCount.get(); } - public static int getNextCodeId() { + static int getNextCodeId() { return methodsCount.getAndIncrement(); } - public int getCodeSize() { + int getCodeSize() { return stubsOffset + getStubCodeSize(); } - public int getStubCodeSize() { + int getStubCodeSize() { return totalStubSize; } - public void setMetadataOffset(int offset) { + void setMetadataOffset(int offset) { this.methodOffsets.setMetadataOffset(offset); } /** * Offset into the code of this method where the stub section starts. */ - public void setStubsOffset(int offset) { + void setStubsOffset(int offset) { stubsOffset = offset; } - public int getStubsOffset() { + int getStubsOffset() { return stubsOffset; } - public void setMetadataGotOffset(int metadataGotOffset) { + void setMetadataGotOffset(int metadataGotOffset) { this.methodOffsets.setMetadataGotOffset(metadataGotOffset); } - public void setMetadataGotSize(int length) { + void setMetadataGotSize(int length) { this.methodOffsets.setMetadataGotSize(length); } - public void addStubCode(String call, StubInformation stub) { + void addStubCode(String call, StubInformation stub) { stubs.put(call, stub); totalStubSize += stub.getSize(); } - public StubInformation getStubFor(String call) { + StubInformation getStubFor(String call) { StubInformation stub = stubs.get(call); assert stub != null : "missing stub for call " + call; stub.verify(); return stub; } - public void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { + void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type); String klassName = type.getName(); @@ -397,11 +300,11 @@ } } - public AOTKlassData getDependentKlassData(String klassName) { + AOTKlassData getDependentKlassData(String klassName) { return dependentKlasses.get(klassName); } - public boolean hasMark(Site call, MarkId id) { + boolean hasMark(Site call, MarkId id) { for (Mark m : compilationResult.getMarks()) { // TODO: X64-specific code. // Call instructions are aligned to 8 @@ -415,11 +318,11 @@ return false; } - public String asTag() { + String asTag() { return "[" + methodInfo.getSymbolName() + "]"; } - public HotSpotCompiledCode compiledCode() { + HotSpotCompiledCode compiledCode() { if (code == null) { code = methodInfo.compiledCode(compilationResult); } @@ -427,12 +330,12 @@ } // Free memory - public void clear() { + void clear() { this.dependentKlasses = null; this.name = null; } - public void clearCompileData() { + void clearCompileData() { this.code = null; this.stubs = null; this.compilationResult = null; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -31,7 +31,7 @@ import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; import jdk.tools.jaotc.binformat.HeaderContainer; -import jdk.tools.jaotc.utils.Timer; + import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.hotspot.HotSpotHostBackend; @@ -42,7 +42,7 @@ import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.hotspot.VMField; -class DataBuilder { +final class DataBuilder { private final Main main; @@ -55,9 +55,9 @@ */ private final BinaryContainer binaryContainer; - private final HashMap vmAddresses = new HashMap<>(); + private static final HashMap vmAddresses = new HashMap<>(); - public DataBuilder(Main main, HotSpotHostBackend backend, List classes, BinaryContainer binaryContainer) { + DataBuilder(Main main, HotSpotHostBackend backend, List classes, BinaryContainer binaryContainer) { this.main = main; this.backend = backend; this.classes = classes; @@ -68,7 +68,7 @@ /** * Returns a value-name map of all {@link VMField} fields. */ - private void fillVMAddresses(HotSpotVMConfigStore config) { + private static void fillVMAddresses(HotSpotVMConfigStore config) { for (VMField vmField : config.getFields().values()) { if (vmField.value != null && vmField.value instanceof Long) { final long address = (Long) vmField.value; @@ -98,7 +98,7 @@ * @param address native address * @return C/C++ functio name associated with the native address */ - public String getVMFunctionNameForAddress(long address) { + static String getVMFunctionNameForAddress(long address) { return vmAddresses.get(address); } @@ -107,7 +107,7 @@ * * @return host backend */ - public HotSpotHostBackend getBackend() { + HotSpotHostBackend getBackend() { return backend; } @@ -116,7 +116,7 @@ * * @return binary container */ - public BinaryContainer getBinaryContainer() { + BinaryContainer getBinaryContainer() { return binaryContainer; } @@ -128,7 +128,7 @@ * @throws Exception */ @SuppressWarnings("try") - public void prepareData(DebugContext debug) throws Exception { + void prepareData(DebugContext debug) throws Exception { try (Timer t = new Timer(main, "Parsing compiled code")) { /* * Copy compiled code into code section container and calls stubs (PLT trampoline). @@ -147,7 +147,7 @@ // Free memory! try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { - main.printMemoryUsage(); + main.printer.printMemoryUsage(); System.gc(); } @@ -163,7 +163,7 @@ // Free memory! try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) { - main.printMemoryUsage(); + main.printer.printMemoryUsage(); System.gc(); } @@ -172,7 +172,7 @@ } try (Timer t = new Timer(main, "Preparing compiled binary")) { // Should be called after Stubs because they can set dependent klasses. - prepareCompiledBinary(metadataBuilder); + prepareCompiledBinary(); } } @@ -203,7 +203,7 @@ /** * Prepare metaspace.offsets section. */ - private void prepareCompiledBinary(MetadataBuilder metadataBuilder) { + private void prepareCompiledBinary() { for (AOTCompiledClass c : classes) { // Create records for compiled AOT methods. c.putMethodsData(binaryContainer); @@ -216,8 +216,8 @@ header.setClassesCount(AOTCompiledClass.getClassesCount()); header.setMethodsCount(CompiledMethodInfo.getMethodsCount()); // Record size of got sections - ByteContainer bc = binaryContainer.getMetaspaceGotContainer(); - header.setMetaspaceGotSize((bc.getByteStreamSize() / 8)); + ByteContainer bc = binaryContainer.getKlassesGotContainer(); + header.setKlassesGotSize((bc.getByteStreamSize() / 8)); bc = binaryContainer.getMetadataGotContainer(); header.setMetadataGotSize((bc.getByteStreamSize() / 8)); bc = binaryContainer.getOopGotContainer(); @@ -232,7 +232,7 @@ // them. ArrayList compiledStubs = compiledClass.getCompiledMethods(); int cntStubs = compiledStubs.size(); - binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer()); + BinaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer()); for (CompiledMethodInfo methodInfo : compiledStubs) { // Note, stubs have different offsets container. methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer()); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -32,7 +32,6 @@ import jdk.tools.jaotc.binformat.Symbol; import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; -import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData; import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; @@ -47,7 +46,7 @@ import jdk.vm.ci.hotspot.HotSpotSentinelConstant; import jdk.vm.ci.meta.VMConstant; -class DataPatchProcessor { +final class DataPatchProcessor { private final TargetDescription target; @@ -89,9 +88,9 @@ gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol; methodInfo.addDependentKlassData(binaryContainer, type); } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) { - targetSymbol = "counters." + MiscUtils.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod()); + targetSymbol = "counters." + JavaMethodInfo.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod()); gotName = "got." + targetSymbol; - binaryContainer.addMetaspaceSymbol(targetSymbol); + binaryContainer.addCountersSymbol(targetSymbol); } } else if (constant instanceof HotSpotObjectConstant) { // String constant. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ELFMacroAssembler.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,7 +23,7 @@ package jdk.tools.jaotc; -import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.StubInformation; import jdk.tools.jaotc.amd64.AMD64ELFMacroAssembler; import jdk.vm.ci.amd64.AMD64; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -37,21 +37,20 @@ */ final class ForeignCallSiteRelocationInfo extends CallSiteRelocationInfo { - ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) { - super(getTargetSymbol(call, callTarget, dataBuilder), getRelocType(callTarget)); + ForeignCallSiteRelocationInfo(Call call, HotSpotForeignCallLinkage callTarget) { + super(getTargetSymbol(call, callTarget), getRelocType(callTarget)); } - private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget, DataBuilder dataBuilder) { + private static String getTargetSymbol(Call call, HotSpotForeignCallLinkage callTarget) { // If it specifies a foreign call linkage, find the symbol corresponding to the address in // HotSpotVMConfig's fields. final long foreignCallTargetAddress = callTarget.getAddress(); // Get the C/C++ function name associated with the foreign call target address. - String functionName = dataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress); + String functionName = DataBuilder.getVMFunctionNameForAddress(foreignCallTargetAddress); if (functionName != null) { // Use the known global AOT symbol associated with function name, if one exists - BinaryContainer binaryContainer = dataBuilder.getBinaryContainer(); - String aotSymbol = binaryContainer.getAOTSymbolForVMFunctionName(functionName); + String aotSymbol = BinaryContainer.getAOTSymbolForVMFunctionName(functionName); if (aotSymbol == null) { throw new InternalError("no global symbol found for: " + functionName); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignCallSiteRelocationSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -32,7 +32,7 @@ */ final class ForeignCallSiteRelocationSymbol extends CallSiteRelocationSymbol { - public ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + ForeignCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { super(binaryContainer.createSymbol(0, Kind.NATIVE_FUNCTION, Binding.GLOBAL, 0, callSiteRelocation.targetSymbol)); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/ForeignGotCallSiteRelocationSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -30,7 +30,7 @@ final class ForeignGotCallSiteRelocationSymbol extends CallSiteRelocationSymbol { - public ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) { + ForeignGotCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, DataBuilder dataBuilder) { super(createPltSymbol(dataBuilder, mi, call, callSiteRelocation)); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -45,7 +45,7 @@ import org.graalvm.compiler.replacements.Snippets; import org.graalvm.word.WordBase; -public class GraalFilters { +final class GraalFilters { private List specialClasses; private List specialArgumentAndReturnTypes; @@ -57,7 +57,7 @@ skipAnnotations.add(MethodSubstitution.class); } - public boolean shouldCompileMethod(ResolvedJavaMethod method) { + boolean shouldCompileMethod(ResolvedJavaMethod method) { // NodeIntrinsics cannot be compiled. if (hasExcludedAnnotation(method)) { return false; @@ -83,7 +83,7 @@ return false; } - public boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) { + boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) { if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) { return false; } @@ -113,7 +113,7 @@ specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess); } - public boolean shouldIgnoreException(Throwable e) { + static boolean shouldIgnoreException(Throwable e) { if (e instanceof GraalError) { String m = e.getMessage(); if (m.contains("ArrayKlass::_component_mirror")) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/InfopointProcessor.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -28,16 +28,14 @@ import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.VirtualObject; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.Infopoint; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.meta.InvokeTarget; -class InfopointProcessor { +final class InfopointProcessor { private final DataBuilder dataBuilder; @@ -70,9 +68,13 @@ default: throw new InternalError("Unknown info point reason: " + info.reason); } - if (info.debugInfo == null) return; + if (info.debugInfo == null) { + return; + } BytecodePosition bcp = info.debugInfo.getBytecodePosition(); - if (bcp == null) return; + if (bcp == null) { + return; + } recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping()); } @@ -82,14 +84,15 @@ recordScopeKlasses(methodInfo, caller, vos); } - HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)bcp.getMethod(); + HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) bcp.getMethod(); HotSpotResolvedObjectType klass = m.getDeclaringClass(); methodInfo.addDependentKlassData(binaryContainer, klass); - if (vos == null) return; - + if (vos == null) { + return; + } for (VirtualObject vo : vos) { - HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType)vo.getType(); + HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType) vo.getType(); methodInfo.addDependentKlassData(binaryContainer, vk); } @@ -116,12 +119,12 @@ /** * Get information about the call site. Name of the callee and relocation call type. */ - private CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) { + private static CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) { InvokeTarget callTarget = call.target; if (callTarget instanceof HotSpotResolvedJavaMethod) { return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget); } else if (callTarget instanceof HotSpotForeignCallLinkage) { - return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget, dataBuilder); + return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget); } else { throw new InternalError("Unhandled call type found in infopoint: " + callTarget); } @@ -136,10 +139,6 @@ return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer); case FOREIGN_CALL_INDIRECT_GOT: return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder); - case FOREIGN_CALL_DIRECT: - case FOREIGN_CALL_DIRECT_FAR: - case FOREIGN_CALL_INDIRECT: - return new ForeignCallSiteRelocationSymbol(callSiteRelocation, binaryContainer); default: return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -34,8 +34,8 @@ */ final class JavaCallSiteRelocationInfo extends CallSiteRelocationInfo { - public JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) { - super(MiscUtils.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT); + JavaCallSiteRelocationInfo(Call call, HotSpotResolvedJavaMethod callTarget) { + super(JavaMethodInfo.uniqueMethodName(callTarget), call.direct ? RelocType.JAVA_CALL_DIRECT : RelocType.JAVA_CALL_INDIRECT); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -25,7 +25,7 @@ import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.Symbol; -import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.StubInformation; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -40,7 +40,7 @@ // -1 represents Universe::non_oop_word() value private static final byte[] minusOneSlot = {-1, -1, -1, -1, -1, -1, -1, -1}; - public JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { super(createPltEntrySymbol(binaryContainer, mi, call, callSiteRelocation)); StubInformation stub = getStub(mi, call); addRelocations(mi, stub, binaryContainer, call, callSiteRelocation); @@ -61,7 +61,7 @@ private static StubInformation getStub(CompiledMethodInfo mi, Call call) { HotSpotResolvedJavaMethod callTarget = (HotSpotResolvedJavaMethod) call.target; - String callTargetSymbol = MiscUtils.uniqueMethodName(callTarget) + ".at." + call.pcOffset; + String callTargetSymbol = JavaMethodInfo.uniqueMethodName(callTarget) + ".at." + call.pcOffset; return mi.getStubFor(callTargetSymbol); } @@ -69,7 +69,7 @@ * Add all the required relocations. */ private static void addRelocations(CompiledMethodInfo mi, StubInformation stub, BinaryContainer binaryContainer, Call call, CallSiteRelocationInfo callSiteRelocation) { - final boolean isVirtualCall = MiscUtils.isVirtualCall(mi, call); + final boolean isVirtualCall = CallInfo.isVirtualCall(mi, call); final int gotStartOffset = binaryContainer.appendExtLinkageGotBytes(zeroSlot, 0, zeroSlot.length); if (isVirtualCall) { @@ -82,7 +82,7 @@ // Add relocation to GOT cell for call resolution jump. // This GOT cell will be initialized during JVM startup with address // of JVM runtime call resolution function. - String gotSymbolName = "got." + getResolveSymbolName(binaryContainer, mi, call); + String gotSymbolName = "got." + getResolveSymbolName(mi, call); Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName); addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset()); @@ -121,16 +121,16 @@ /** * Returns the name of the resolve method for this particular call. */ - private static String getResolveSymbolName(BinaryContainer binaryContainer, CompiledMethodInfo mi, Call call) { + private static String getResolveSymbolName(CompiledMethodInfo mi, Call call) { String resolveSymbolName; - if (MiscUtils.isStaticCall(call)) { - resolveSymbolName = binaryContainer.getResolveStaticEntrySymbolName(); - } else if (MiscUtils.isSpecialCall(call)) { - resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName(); - } else if (MiscUtils.isOptVirtualCall(mi, call)) { - resolveSymbolName = binaryContainer.getResolveOptVirtualEntrySymbolName(); - } else if (MiscUtils.isVirtualCall(mi, call)) { - resolveSymbolName = binaryContainer.getResolveVirtualEntrySymbolName(); + if (CallInfo.isStaticCall(call)) { + resolveSymbolName = BinaryContainer.getResolveStaticEntrySymbolName(); + } else if (CallInfo.isSpecialCall(call)) { + resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName(); + } else if (CallInfo.isOptVirtualCall(mi, call)) { + resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName(); + } else if (CallInfo.isVirtualCall(mi, call)) { + resolveSymbolName = BinaryContainer.getResolveVirtualEntrySymbolName(); } else { throw new InternalError("Unknown call type in " + mi.asTag() + " @ " + call.pcOffset + " for call" + call.target); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaMethodInfo.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -24,9 +24,11 @@ package jdk.tools.jaotc; import org.graalvm.compiler.code.CompilationResult; -import jdk.vm.ci.hotspot.HotSpotCompiledCode; -public interface JavaMethodInfo { +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +interface JavaMethodInfo { /** * @return unique symbol name for this method. @@ -42,4 +44,16 @@ HotSpotCompiledCode compiledCode(CompilationResult result); + /** + * Name a java method with class and signature to make it unique. + * + * @param method to generate unique identifier for + * @return Unique name for this method including class and signature + **/ + static String uniqueMethodName(ResolvedJavaMethod method) { + String className = method.getDeclaringClass().toClassName(); + String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor(); + return name; + } + } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,208 @@ +/* + * 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. + */ + +package jdk.tools.jaotc; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Stream; + +final class Linker { + + private final Options options; + private String objectFileName; + private String libraryFileName; + private String linkerCmd; + + String objFile() { + return objectFileName; + } + + String libFile() { + return libraryFileName; + } + + Linker(Main main) throws Exception { + this.options = main.options; + String name = options.outputName; + objectFileName = name; + libraryFileName = name; + + if (options.linkerpath != null && !(new File(options.linkerpath).exists())) { + throw new InternalError("Invalid linker path: " + options.linkerpath); + } + String linkerPath; + String linkerCheck; + + switch (options.osName) { + case "Linux": + if (name.endsWith(".so")) { + objectFileName = name.substring(0, name.length() - ".so".length()); + } + linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; + linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName; + linkerCheck = linkerPath + " -v"; + break; + case "SunOS": + if (name.endsWith(".so")) { + objectFileName = name.substring(0, name.length() - ".so".length()); + } + objectFileName = objectFileName + ".o"; + linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; + linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName; + linkerCheck = linkerPath + " -V"; + break; + case "Mac OS X": + if (name.endsWith(".dylib")) { + objectFileName = name.substring(0, name.length() - ".dylib".length()); + } + objectFileName = objectFileName + ".o"; + linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; + linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName; + linkerCheck = linkerPath + " -v"; + break; + default: + if (options.osName.startsWith("Windows")) { + if (name.endsWith(".dll")) { + objectFileName = name.substring(0, name.length() - ".dll".length()); + } + objectFileName = objectFileName + ".obj"; + linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath(); + if (linkerPath == null) { + throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe"); + } + linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName; + linkerCheck = null; // link.exe presence is verified already + break; + } else { + throw new InternalError("Unsupported platform: " + options.osName); + } + } + + // Check linker presence on platforms by printing its version + if (linkerCheck != null) { + Process p = Runtime.getRuntime().exec(linkerCheck); + final int exitCode = p.waitFor(); + if (exitCode != 0) { + InputStream stderr = p.getErrorStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(stderr)); + Stream lines = br.lines(); + StringBuilder sb = new StringBuilder(); + lines.iterator().forEachRemaining(e -> sb.append(e)); + throw new InternalError(sb.toString()); + } + } + } + + void link() throws Exception { + Process p = Runtime.getRuntime().exec(linkerCmd); + final int exitCode = p.waitFor(); + if (exitCode != 0) { + InputStream stderr = p.getErrorStream(); + if (stderr.read() == -1) { + stderr = p.getInputStream(); + } + BufferedReader br = new BufferedReader(new InputStreamReader(stderr)); + Stream lines = br.lines(); + StringBuilder sb = new StringBuilder(); + lines.iterator().forEachRemaining(e -> sb.append(e)); + throw new InternalError(sb.toString()); + } + File objFile = new File(objectFileName); + if (objFile.exists()) { + if (!objFile.delete()) { + throw new InternalError("Failed to delete " + objectFileName + " file"); + } + } + // Make non-executable for all. + File libFile = new File(libraryFileName); + if (libFile.exists() && !options.osName.startsWith("Windows")) { + if (!libFile.setExecutable(false, false)) { + throw new InternalError("Failed to change attribute for " + libraryFileName + " file"); + } + } + + } + + /** + * Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012 + */ + public enum VSVERSIONS { + VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"), + VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"), + VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe"); + + private final String envvariable; + private final String wkp; + + VSVERSIONS(String envvariable, String wellknownpath) { + this.envvariable = envvariable; + this.wkp = wellknownpath; + } + + String EnvVariable() { + return envvariable; + } + + String WellKnownPath() { + return wkp; + } + } + + /** + * Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012 + */ + private static String getWindowsLinkPath() { + String link = "\\VC\\bin\\amd64\\link.exe"; + + /** + * First try searching the paths pointed to by the VS environment variables. + */ + for (VSVERSIONS vs : VSVERSIONS.values()) { + String vspath = System.getenv(vs.EnvVariable()); + if (vspath != null) { + File commonTools = new File(vspath); + File vsRoot = commonTools.getParentFile().getParentFile(); + File linkPath = new File(vsRoot, link); + if (linkPath.exists()) { + return linkPath.getPath(); + } + } + } + + /** + * If we didn't find via the VS environment variables, try the well known paths + */ + for (VSVERSIONS vs : VSVERSIONS.values()) { + String wkp = vs.WellKnownPath(); + if (new File(wkp).exists()) { + return wkp; + } + } + + return null; + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,4 +1,4 @@ -package jdk.tools.jaotc;/* +/* * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -21,6 +21,8 @@ * questions. */ +package jdk.tools.jaotc; + public class LoadedClass { private final String name; private final Class clz; @@ -45,12 +47,17 @@ @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof LoadedClass)) return false; - + if (this == o) { + return true; + } + if (!(o instanceof LoadedClass)) { + return false; + } LoadedClass that = (LoadedClass) o; - if (name != null ? !name.equals(that.name) : that.name != null) return false; + if (name != null ? !name.equals(that.name) : that.name != null) { + return false; + } return clz != null ? clz.equals(that.clz) : that.clz == null; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LogPrinter.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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,12 +23,174 @@ package jdk.tools.jaotc; -public interface LogPrinter { - void printInfo(String s); +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.Date; + +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.binformat.BinaryContainer; + +final class LogPrinter { + + private static FileWriter logFile = null; + private final Options options; + private final PrintWriter log; + + LogPrinter(Main main, PrintWriter log) { + this.options = main.options; + this.log = log; + } + + void printInfo(String message) { + if (options.info) { + log.print(message); + log.flush(); + } + } + + void printlnInfo(String message) { + if (options.info) { + log.println(message); + log.flush(); + } + } - void printlnVerbose(String s); + void printVerbose(String message) { + if (options.verbose) { + log.print(message); + log.flush(); + } + } + + void printlnVerbose(String message) { + if (options.verbose) { + log.println(message); + log.flush(); + } + } + + void printDebug(String message) { + if (options.debug) { + log.print(message); + log.flush(); + } + } + + void printlnDebug(String message) { + if (options.debug) { + log.println(message); + log.flush(); + } + } + + void printError(String message) { + log.println("Error: " + message); + log.flush(); + } + + void reportError(Throwable e) { + log.println("Error: " + e.getMessage()); + if (options.info) { + e.printStackTrace(log); + } + log.flush(); + } + + void reportError(String key, Object... args) { + printError(MessageFormat.format(key, args)); + } + + private static String humanReadableByteCount(long bytes) { + int unit = 1024; - void printlnInfo(String s); + if (bytes < unit) { + return bytes + " B"; + } + + int exp = (int) (Math.log(bytes) / Math.log(unit)); + char pre = "KMGTPE".charAt(exp - 1); + return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre); + } + + void printMemoryUsage() { + if (options.verbose) { + MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); + log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]", + humanReadableByteCount(memusage.getUsed()), + humanReadableByteCount(memusage.getCommitted()), + freeratio * 100); + } + } + + private void printContainerInfo(ByteContainer container) { + printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes"); + } + + void containersInfo(BinaryContainer binaryContainer) { + printContainerInfo(binaryContainer.getHeaderContainer().getContainer()); + printContainerInfo(binaryContainer.getConfigContainer()); + printContainerInfo(binaryContainer.getKlassesOffsetsContainer()); + printContainerInfo(binaryContainer.getMethodsOffsetsContainer()); + printContainerInfo(binaryContainer.getKlassesDependenciesContainer()); + printContainerInfo(binaryContainer.getStubsOffsetsContainer()); + printContainerInfo(binaryContainer.getMethodMetadataContainer()); + printContainerInfo(binaryContainer.getCodeContainer()); + printContainerInfo(binaryContainer.getCodeSegmentsContainer()); + printContainerInfo(binaryContainer.getConstantDataContainer()); + printContainerInfo(binaryContainer.getKlassesGotContainer()); + printContainerInfo(binaryContainer.getCountersGotContainer()); + printContainerInfo(binaryContainer.getMetadataGotContainer()); + printContainerInfo(binaryContainer.getMethodStateContainer()); + printContainerInfo(binaryContainer.getOopGotContainer()); + printContainerInfo(binaryContainer.getMetaspaceNamesContainer()); + } - void printError(String s); + static void openLog() { + int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0); + if (v == 0) { + logFile = null; + return; + } + // Create log file in current directory + String fileName = "aot_compilation" + new Date().getTime() + ".log"; + Path logFilePath = Paths.get("./", fileName); + String logFileName = logFilePath.toString(); + try { + // Create file to which we do not append + logFile = new FileWriter(logFileName, false); + } catch (IOException e) { + System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created"); + logFile = null; + } + } + + static void writeLog(String str) { + if (logFile != null) { + try { + logFile.write(str + "\n"); + logFile.flush(); + } catch (IOException e) { + // Print to console + System.out.println(str + "\n"); + } + } + } + + static void closeLog() { + if (logFile != null) { + try { + logFile.close(); + } catch (IOException e) { + // Do nothing + } + } + } + } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java Tue Sep 05 10:09:44 2017 -0700 @@ -27,37 +27,14 @@ import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.PrintWriter; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryUsage; -import java.nio.file.Path; -import java.nio.file.Paths; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; -import java.util.stream.Stream; import jdk.tools.jaotc.binformat.BinaryContainer; -import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.collect.*; -import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; -import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; -import jdk.tools.jaotc.collect.jar.JarSourceProvider; -import jdk.tools.jaotc.collect.module.ModuleSourceProvider; -import jdk.tools.jaotc.utils.Timer; +import jdk.tools.jaotc.Options.Option; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; @@ -80,227 +57,14 @@ import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.runtime.JVMCI; -public class Main implements LogPrinter { - static class BadArgs extends Exception { - private static final long serialVersionUID = 1L; - final String key; - final Object[] args; - boolean showUsage; - - BadArgs(String key, Object... args) { - super(MessageFormat.format(key, args)); - this.key = key; - this.args = args; - } - - BadArgs showUsage(boolean b) { - showUsage = b; - return this; - } - } - - abstract static class Option { - final String help; - final boolean hasArg; - final String[] aliases; - - Option(String help, boolean hasArg, String... aliases) { - this.help = help; - this.hasArg = hasArg; - this.aliases = aliases; - } - - boolean isHidden() { - return false; - } - - boolean matches(String opt) { - for (String a : aliases) { - if (a.equals(opt)) { - return true; - } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { - return true; - } - } - return false; - } - - boolean ignoreRest() { - return false; - } - - abstract void process(Main task, String opt, String arg) throws BadArgs; - } +public final class Main { - static Option[] recognizedOptions = {new Option(" --output Output file name", true, "--output") { - @Override - void process(Main task, String opt, String arg) { - String name = arg; - task.options.outputName = name; - } - }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") { - @Override - void process(Main task, String opt, String arg) { - task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); - } - }, new Option(" --jar List of jar files to compile", true, "--jar") { - @Override - void process(Main task, String opt, String arg) { - task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); - } - }, new Option(" --module List of modules to compile", true, "--module") { - @Override - void process(Main task, String opt, String arg) { - task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); - } - }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") { - @Override - void process(Main task, String opt, String arg) { - task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); - } - }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") { - @Override - void process(Main task, String opt, String arg) { - String[] elements = arg.split(":"); - task.options.searchPath.add(elements); - } - }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { - @Override - void process(Main task, String opt, String arg) { - task.options.methodList = arg; - } - }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { - @Override - void process(Main task, String opt, String arg) { - task.options.tiered = true; - } - }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { - @Override - void process(Main task, String opt, String arg) { - task.options.compileWithAssertions = true; - } - }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") { - @Override - void process(Main task, String opt, String arg) { - int threads = Integer.parseInt(arg); - final int available = Runtime.getRuntime().availableProcessors(); - if (threads <= 0) { - task.warning("invalid number of threads specified: {0}, using: {1}", threads, available); - threads = available; - } - if (threads > available) { - task.warning("too many threads specified: {0}, limiting to: {1}", threads, available); - } - task.options.threads = Integer.min(threads, available); - } - }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") { - @Override - void process(Main task, String opt, String arg) { - task.options.ignoreClassLoadingErrors = true; - } - }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") { - @Override - void process(Main task, String opt, String arg) { - task.options.exitOnError = true; - } - }, new Option(" --info Print information during compilation", false, "--info") { - @Override - void process(Main task, String opt, String arg) throws BadArgs { - task.options.info = true; - } - }, new Option(" --verbose Print verbose information", false, "--verbose") { - @Override - void process(Main task, String opt, String arg) throws BadArgs { - task.options.info = true; - task.options.verbose = true; - } - }, new Option(" --debug Print debug information", false, "--debug") { - @Override - void process(Main task, String opt, String arg) throws BadArgs { - task.options.info = true; - task.options.verbose = true; - task.options.debug = true; - } - }, new Option(" --help Print this usage message", false, "--help") { - @Override - void process(Main task, String opt, String arg) { - task.options.help = true; - } - }, new Option(" --version Version information", false, "--version") { - @Override - void process(Main task, String opt, String arg) { - task.options.version = true; - } - }, new Option(" --linker-path Full path to linker executable", true, "--linker-path") { - @Override - void process(Main task, String opt, String arg) { - task.options.linkerpath = arg; - } - }, new Option(" -J Pass directly to the runtime system", false, "-J") { - @Override - void process(Main task, String opt, String arg) { - } - }}; - - public static class Options { - public List files = new LinkedList<>(); - public String outputName = defaultOutputName(); - public String methodList; - public List sources = new ArrayList<>(); - public String linkerpath = null; - public SearchPath searchPath = new SearchPath(); - - /** - * We don't see scaling beyond 16 threads. - */ - private static final int COMPILER_THREADS = 16; - - public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); - - public boolean ignoreClassLoadingErrors; - public boolean exitOnError; - public boolean info; - public boolean verbose; - public boolean debug; - public boolean help; - public boolean version; - public boolean compileWithAssertions; - public boolean tiered; - - private static String defaultOutputName() { - String osName = System.getProperty("os.name"); - String name = "unnamed."; - String ext; - - switch (osName) { - case "Linux": - case "SunOS": - ext = "so"; - break; - case "Mac OS X": - ext = "dylib"; - break; - default: - if (osName.startsWith("Windows")) { - ext = "dll"; - } else { - ext = "so"; - } - } - - return name + ext; - } - } - - /* package */final Options options = new Options(); - - /** - * Logfile. - */ - private static FileWriter logFile = null; + final Options options = new Options(); + private PrintWriter log; + LogPrinter printer; + GraalFilters filters; private static final int EXIT_OK = 0; // No errors. private static final int EXIT_CMDERR = 2; // Bad command-line arguments and/or switches. @@ -317,12 +81,11 @@ } private int run(String[] args) { - if (log == null) { - log = new PrintWriter(System.out); - } + log = new PrintWriter(System.out); + printer = new LogPrinter(this, log); try { - handleOptions(args); + Options.handleOptions(this, args); if (options.help) { showHelp(); return EXIT_OK; @@ -332,17 +95,17 @@ return EXIT_OK; } - printlnInfo("Compiling " + options.outputName + "..."); + printer.printlnInfo("Compiling " + options.outputName + "..."); final long start = System.currentTimeMillis(); if (!run()) { return EXIT_ABNORMAL; } final long end = System.currentTimeMillis(); - printlnInfo("Total time: " + (end - start) + " ms"); + printer.printlnInfo("Total time: " + (end - start) + " ms"); return EXIT_OK; - } catch (BadArgs e) { - reportError(e.key, e.args); + } catch (Options.BadArgs e) { + printer.reportError(e.key, e.args); if (e.showUsage) { showUsage(); } @@ -355,117 +118,20 @@ } } - private static String humanReadableByteCount(long bytes) { - int unit = 1024; - - if (bytes < unit) { - return bytes + " B"; - } - - int exp = (int) (Math.log(bytes) / Math.log(unit)); - char pre = "KMGTPE".charAt(exp - 1); - return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre); - } - - void printMemoryUsage() { - if (options.verbose) { - MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); - log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]", - humanReadableByteCount(memusage.getUsed()), - humanReadableByteCount(memusage.getCommitted()), - freeratio * 100); - } - } - - /** - * Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012 - */ - public enum VSVERSIONS { - VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"), - VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"), - VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe"); - - private final String envvariable; - private final String wkp; - - VSVERSIONS(String envvariable, String wellknownpath) { - this.envvariable = envvariable; - this.wkp = wellknownpath; - } - - String EnvVariable() { - return envvariable; - } - - String WellKnownPath() { - return wkp; - } - } - - /** - * Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012 - */ - private static String getWindowsLinkPath() { - String link = "\\VC\\bin\\amd64\\link.exe"; - - /** - * First try searching the paths pointed to by the VS environment variables. - */ - for (VSVERSIONS vs : VSVERSIONS.values()) { - String vspath = System.getenv(vs.EnvVariable()); - if (vspath != null) { - File commonTools = new File(vspath); - File vsRoot = commonTools.getParentFile().getParentFile(); - File linkPath = new File(vsRoot, link); - if (linkPath.exists()) - return linkPath.getPath(); - } - } - - /** - * If we didn't find via the VS environment variables, try the well known paths - */ - for (VSVERSIONS vs : VSVERSIONS.values()) { - String wkp = vs.WellKnownPath(); - if (new File(wkp).exists()) { - return wkp; - } - } - - return null; - } - @SuppressWarnings("try") private boolean run() throws Exception { - openLog(); + LogPrinter.openLog(); try { - CompilationSpec compilationRestrictions = collectSpecifiedMethods(); - Set> classesToCompile = new HashSet<>(); + final Linker linker = new Linker(this); + final String objectFileName = linker.objFile(); + final Collector collector = new Collector(this); + Set> classesToCompile; try (Timer t = new Timer(this, "")) { - FileSupport fileSupport = new FileSupport(); - ClassSearch lookup = new ClassSearch(); - lookup.addProvider(new ModuleSourceProvider()); - lookup.addProvider(new ClassNameSourceProvider(fileSupport)); - lookup.addProvider(new JarSourceProvider()); - lookup.addProvider(new DirectorySourceProvider(fileSupport)); - - List found = null; - try { - found = lookup.search(options.files, options.searchPath); - } catch (InternalError e) { - reportError(e); - return false; - } - - for (LoadedClass loadedClass : found) { - classesToCompile.add(loadedClass.getLoadedClass()); - } - - printInfo(classesToCompile.size() + " classes found"); + classesToCompile = collector.collectClassesToCompile(); + printer.printInfo(classesToCompile.size() + " classes found"); } OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; @@ -478,23 +144,22 @@ HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime(); HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend(); MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); - GraalFilters filters = new GraalFilters(metaAccess); + filters = new GraalFilters(metaAccess); List classes; try (Timer t = new Timer(this, "")) { - classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess); + classes = collector.collectMethodsToCompile(classesToCompile, metaAccess); } // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { - printMemoryUsage(); - compilationRestrictions = null; + printer.printMemoryUsage(); classesToCompile = null; System.gc(); } - AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, filters); + AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend); SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection(); AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads); classes = compiler.compileClasses(classes); @@ -506,7 +171,7 @@ // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { - printMemoryUsage(); + printer.printMemoryUsage(); aotBackend = null; compiler = null; System.gc(); @@ -520,25 +185,11 @@ } // Print information about section sizes - printContainerInfo(binaryContainer.getHeaderContainer().getContainer()); - printContainerInfo(binaryContainer.getConfigContainer()); - printContainerInfo(binaryContainer.getKlassesOffsetsContainer()); - printContainerInfo(binaryContainer.getMethodsOffsetsContainer()); - printContainerInfo(binaryContainer.getKlassesDependenciesContainer()); - printContainerInfo(binaryContainer.getStubsOffsetsContainer()); - printContainerInfo(binaryContainer.getMethodMetadataContainer()); - printContainerInfo(binaryContainer.getCodeContainer()); - printContainerInfo(binaryContainer.getCodeSegmentsContainer()); - printContainerInfo(binaryContainer.getConstantDataContainer()); - printContainerInfo(binaryContainer.getMetaspaceGotContainer()); - printContainerInfo(binaryContainer.getMetadataGotContainer()); - printContainerInfo(binaryContainer.getMethodStateContainer()); - printContainerInfo(binaryContainer.getOopGotContainer()); - printContainerInfo(binaryContainer.getMetaspaceNamesContainer()); + printer.containersInfo(binaryContainer); // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { - printMemoryUsage(); + printer.printMemoryUsage(); backend = null; for (AOTCompiledClass aotCompClass : classes) { aotCompClass.clear(); @@ -550,238 +201,59 @@ System.gc(); } - String name = options.outputName; - String objectFileName = name; - - String libraryFileName = name; - - String linkerCmd; - String linkerPath; - String osName = System.getProperty("os.name"); - - switch (osName) { - case "Linux": - if (name.endsWith(".so")) { - objectFileName = name.substring(0, name.length() - ".so".length()); - } - linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; - linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName; - break; - case "SunOS": - if (name.endsWith(".so")) { - objectFileName = name.substring(0, name.length() - ".so".length()); - } - objectFileName = objectFileName + ".o"; - linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; - linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName; - break; - case "Mac OS X": - if (name.endsWith(".dylib")) { - objectFileName = name.substring(0, name.length() - ".dylib".length()); - } - objectFileName = objectFileName + ".o"; - linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; - linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName; - break; - default: - if (osName.startsWith("Windows")) { - if (name.endsWith(".dll")) { - objectFileName = name.substring(0, name.length() - ".dll".length()); - } - objectFileName = objectFileName + ".obj"; - linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath(); - if (linkerPath == null) { - throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe"); - } - linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName; - break; - } else { - throw new InternalError("Unsupported platform: " + osName); - } - } - try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) { - binaryContainer.createBinary(objectFileName, JVM_VERSION); + binaryContainer.createBinary(objectFileName); } // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { - printMemoryUsage(); + printer.printMemoryUsage(); binaryContainer = null; System.gc(); } - try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) { - Process p = Runtime.getRuntime().exec(linkerCmd); - final int exitCode = p.waitFor(); - if (exitCode != 0) { - InputStream stderr = p.getErrorStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(stderr)); - Stream lines = br.lines(); - StringBuilder sb = new StringBuilder(); - lines.iterator().forEachRemaining(e -> sb.append(e)); - throw new InternalError(sb.toString()); - } - File objFile = new File(objectFileName); - if (objFile.exists()) { - if (!objFile.delete()) { - throw new InternalError("Failed to delete " + objectFileName + " file"); - } - } - // Make non-executable for all. - File libFile = new File(libraryFileName); - if (libFile.exists() && !osName.startsWith("Windows")) { - if (!libFile.setExecutable(false, false)) { - throw new InternalError("Failed to change attribute for " + libraryFileName + " file"); - } - } + try (Timer t = new Timer(this, "Creating shared library: " + linker.libFile())) { + linker.link(); } - printVerbose("Final memory "); - printMemoryUsage(); - printlnVerbose(""); + printer.printVerbose("Final memory "); + printer.printMemoryUsage(); + printer.printlnVerbose(""); } finally { - closeLog(); + LogPrinter.closeLog(); } return true; } - private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { - for (ResolvedJavaMethod m : methods) { - addMethod(aotClass, m, compilationRestrictions, filters); - } - } + void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) { + String methodName = JavaMethodInfo.uniqueMethodName(resolvedMethod); - private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) { - // Don't compile native or abstract methods. - if (!method.hasBytecodes()) { - return; + if (options.debug) { + printer.printError("Failed compilation: " + methodName + ": " + e); } - if (!compilationRestrictions.shouldCompileMethod(method)) { - return; - } - if (!filters.shouldCompileMethod(method)) { + + // Ignore some exceptions when meta-compiling Graal. + if (GraalFilters.shouldIgnoreException(e)) { return; } - aotClass.addMethod(method); - printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor()); - } + LogPrinter.writeLog("Failed compilation of method " + methodName + message); - private void printContainerInfo(ByteContainer container) { - printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes"); - } - - PrintWriter log; - - private void handleOptions(String[] args) throws BadArgs { - if (args.length == 0) { - options.help = true; - return; + if (!options.debug) { + printer.printError("Failed compilation: " + methodName + ": " + e); } - // Make checkstyle happy. - int i = 0; - for (; i < args.length; i++) { - String arg = args[i]; - - if (arg.charAt(0) == '-') { - Option option = getOption(arg); - String param = null; + if (options.verbose) { + e.printStackTrace(log); + } - if (option.hasArg) { - if (arg.startsWith("--") && arg.indexOf('=') > 0) { - param = arg.substring(arg.indexOf('=') + 1, arg.length()); - } else if (i + 1 < args.length) { - param = args[++i]; - } - - if (param == null || param.isEmpty() || param.charAt(0) == '-') { - throw new BadArgs("missing argument for option: {0}", arg).showUsage(true); - } - } - - option.process(this, arg, param); - - if (option.ignoreRest()) { - break; - } - } else { - options.files.add(new SearchFor(arg)); - } + if (options.exitOnError) { + System.exit(1); } } - private static Option getOption(String name) throws BadArgs { - for (Option o : recognizedOptions) { - if (o.matches(name)) { - return o; - } - } - throw new BadArgs("unknown option: {0}", name).showUsage(true); - } - - public void printInfo(String message) { - if (options.info) { - log.print(message); - log.flush(); - } - } - - public void printlnInfo(String message) { - if (options.info) { - log.println(message); - log.flush(); - } - } - - public void printVerbose(String message) { - if (options.verbose) { - log.print(message); - log.flush(); - } - } - - public void printlnVerbose(String message) { - if (options.verbose) { - log.println(message); - log.flush(); - } - } - - public void printDebug(String message) { - if (options.debug) { - log.print(message); - log.flush(); - } - } - - public void printlnDebug(String message) { - if (options.debug) { - log.println(message); - log.flush(); - } - } - - public void printError(String message) { - log.println("Error: " + message); - log.flush(); - } - - private void reportError(Throwable e) { - log.println("Error: " + e.getMessage()); - if (options.info) { - e.printStackTrace(log); - } - log.flush(); - } - - private void reportError(String key, Object... args) { - printError(MessageFormat.format(key, args)); - } - - private void warning(String key, Object... args) { + void warning(String key, Object... args) { log.println("Warning: " + MessageFormat.format(key, args)); log.flush(); } @@ -789,6 +261,7 @@ private void showUsage() { log.println("Usage: " + PROGNAME + " list"); log.println("use --help for a list of possible options"); + log.flush(); } private void showHelp() { @@ -798,7 +271,7 @@ log.println(" or directories which contain class files."); log.println(); log.println("where options include:"); - for (Option o : recognizedOptions) { + for (Option o : Options.recognizedOptions) { String name = o.aliases[0].substring(1); // there must always be at least one name name = name.charAt(0) == '-' ? name.substring(1) : name; if (o.isHidden() || name.equals("h")) { @@ -806,169 +279,10 @@ } log.println(o.help); } + log.flush(); } private void showVersion() { log.println(PROGNAME + " " + JVM_VERSION); } - - /** - * Collect all method we should compile. - * - * @return array list of AOT classes which have compiled methods. - */ - private List collectMethodsToCompile(Set> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) { - int total = 0; - int count = 0; - List classes = new ArrayList<>(); - - for (Class c : classesToCompile) { - ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c); - if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) { - AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType); - printlnVerbose(" Scanning " + c.getName()); - - // Constructors - try { - ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors(); - addMethods(aotClass, ctors, compilationRestrictions, filters); - total += ctors.length; - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - printError(c.getName() + ": " + e); - } else { - throw new InternalError(e); - } - } - - // Methods - try { - ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods(); - addMethods(aotClass, methods, compilationRestrictions, filters); - total += methods.length; - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - printError(c.getName() + ": " + e); - } else { - throw new InternalError(e); - } - } - - // Class initializer - try { - ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer(); - if (clinit != null) { - addMethod(aotClass, clinit, compilationRestrictions, filters); - total++; - } - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - printError(c.getName() + ": " + e); - } else { - throw new InternalError(e); - } - } - - // Found any methods to compile? Add the class. - if (aotClass.hasMethods()) { - classes.add(aotClass); - count += aotClass.getMethodCount(); - } - } - } - printInfo(total + " methods total, " + count + " methods to compile"); - return classes; - } - - /** - * If a file with compilation limitations is specified using the java property - * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions. - */ - private CompilationSpec collectSpecifiedMethods() { - CompilationSpec compilationRestrictions = new CompilationSpec(); - String methodListFileName = options.methodList; - - if (methodListFileName != null && !methodListFileName.equals("")) { - try { - FileReader methListFile = new FileReader(methodListFileName); - BufferedReader readBuf = new BufferedReader(methListFile); - String line = null; - while ((line = readBuf.readLine()) != null) { - String trimmedLine = line.trim(); - if (!trimmedLine.startsWith("#")) { - String[] components = trimmedLine.split(" "); - if (components.length == 2) { - String directive = components[0]; - String pattern = components[1]; - switch (directive) { - case "compileOnly": - compilationRestrictions.addCompileOnlyPattern(pattern); - break; - case "exclude": - compilationRestrictions.addExcludePattern(pattern); - break; - default: - System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName); - } - } else { - if (!trimmedLine.equals("")) { - System.out.println("Ignoring malformed line:\n\t " + line + "\n"); - } - } - } - } - readBuf.close(); - } catch (FileNotFoundException e) { - throw new InternalError("Unable to open method list file: " + methodListFileName, e); - } catch (IOException e) { - throw new InternalError("Unable to read method list file: " + methodListFileName, e); - } - } - - return compilationRestrictions; - } - - private static void openLog() { - int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0); - if (v == 0) { - logFile = null; - return; - } - // Create log file in current directory - String fileName = "aot_compilation" + new Date().getTime() + ".log"; - Path logFilePath = Paths.get("./", fileName); - String logFileName = logFilePath.toString(); - try { - // Create file to which we do not append - logFile = new FileWriter(logFileName, false); - } catch (IOException e) { - System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created"); - logFile = null; - } - } - - public static void writeLog(String str) { - if (logFile != null) { - try { - logFile.write(str + "\n"); - logFile.flush(); - } catch (IOException e) { - // Print to console - System.out.println(str + "\n"); - } - } - } - - public static void closeLog() { - if (logFile != null) { - try { - logFile.close(); - } catch (IOException e) { - // Do nothing - } - } - } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -59,7 +59,7 @@ this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name); } - public static MarkId getEnum(int value) { + static MarkId getEnum(int value) { for (MarkId e : values()) { if (e.value == value) { return e; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -30,7 +30,7 @@ import jdk.vm.ci.code.site.Mark; -class MarkProcessor { +final class MarkProcessor { private final BinaryContainer binaryContainer; @@ -65,31 +65,31 @@ switch (markId) { case POLL_FAR: case POLL_RETURN_FAR: - vmSymbolName = binaryContainer.getPollingPageSymbolName(); + vmSymbolName = BinaryContainer.getPollingPageSymbolName(); break; case CARD_TABLE_ADDRESS: - vmSymbolName = binaryContainer.getCardTableAddressSymbolName(); + vmSymbolName = BinaryContainer.getCardTableAddressSymbolName(); break; case HEAP_TOP_ADDRESS: - vmSymbolName = binaryContainer.getHeapTopAddressSymbolName(); + vmSymbolName = BinaryContainer.getHeapTopAddressSymbolName(); break; case HEAP_END_ADDRESS: - vmSymbolName = binaryContainer.getHeapEndAddressSymbolName(); + vmSymbolName = BinaryContainer.getHeapEndAddressSymbolName(); break; case NARROW_KLASS_BASE_ADDRESS: - vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName(); + vmSymbolName = BinaryContainer.getNarrowKlassBaseAddressSymbolName(); break; case NARROW_OOP_BASE_ADDRESS: - vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName(); + vmSymbolName = BinaryContainer.getNarrowOopBaseAddressSymbolName(); break; case CRC_TABLE_ADDRESS: - vmSymbolName = binaryContainer.getCrcTableAddressSymbolName(); + vmSymbolName = BinaryContainer.getCrcTableAddressSymbolName(); break; case LOG_OF_HEAP_REGION_GRAIN_BYTES: - vmSymbolName = binaryContainer.getLogOfHeapRegionGrainBytesSymbolName(); + vmSymbolName = BinaryContainer.getLogOfHeapRegionGrainBytesSymbolName(); break; case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: - vmSymbolName = binaryContainer.getInlineContiguousAllocationSupportedSymbolName(); + vmSymbolName = BinaryContainer.getInlineContiguousAllocationSupportedSymbolName(); break; default: throw new InternalError("Unhandled mark: " + mark); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -28,10 +28,7 @@ import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.binformat.Symbol.Binding; -import jdk.tools.jaotc.binformat.Symbol.Kind; import jdk.tools.jaotc.binformat.GotSymbol; -import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData; import jdk.tools.jaotc.utils.NativeOrderOutputStream; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; @@ -43,7 +40,7 @@ import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotMetaData; -class MetadataBuilder { +final class MetadataBuilder { private final DataBuilder dataBuilder; @@ -58,8 +55,6 @@ * Process compiled methods and create method metadata. */ void processMetadata(List classes, AOTCompiledClass stubCompiledCode) { - binaryContainer.getMethodMetadataContainer().createSymbol(0, Kind.OBJECT, Binding.LOCAL, 0, "metaStart"); - for (AOTCompiledClass c : classes) { processMetadataClass(c); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MiscUtils.java Sun Sep 03 19:31:11 2017 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.tools.jaotc; - -import org.graalvm.compiler.bytecode.Bytecodes; - -import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.code.site.Call; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class MiscUtils { - - /** - * Name a java method with class and signature to make it unique. - * - * @param method to generate unique identifier for - * @return Unique name for this method including class and signature - **/ - public static String uniqueMethodName(ResolvedJavaMethod method) { - String className = method.getDeclaringClass().toClassName(); - String name = className + "." + method.getName() + method.getSignature().toMethodDescriptor(); - return name; - } - - public static boolean isStaticCall(Call call) { - if (isJavaCall(call)) { - return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESTATIC); - } - return false; - } - - public static boolean isSpecialCall(Call call) { - if (isJavaCall(call)) { - return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKESPECIAL); - } - return false; - } - - private static boolean isInvokeVirtual(Call call) { - if (isJavaCall(call)) { - return ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEVIRTUAL) || ((getByteCode(call) & 0xFF) == Bytecodes.INVOKEINTERFACE); - } - return false; - } - - public static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) { - return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL); - } - - public static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) { - return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL); - } - - private static boolean isJavaCall(Call call) { - // If there is no associated debug info return false - if (call.debugInfo == null) { - return false; - } - BytecodePosition bcpos = call.debugInfo.getBytecodePosition(); - ResolvedJavaMethod method = bcpos.getMethod(); - // If bytecode position indicates a special value (negative value) it is - // not a normal java call - if (bcpos.getBCI() < 0) { - return false; - } - // If there is no method associated with the debuginfo, return false - if (method == null) { - return false; - } - assert (method instanceof HotSpotResolvedJavaMethod) : "Not a resolved Java call"; - return true; - } - - private static byte getByteCode(Call call) { - ResolvedJavaMethod m = call.debugInfo.getBytecodePosition().getMethod(); - int callPosition = call.debugInfo.getBytecodePosition().getBCI(); - byte[] code = m.getCode(); - return code[callPosition]; - } - -} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,297 @@ +/* + * 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. + */ + +package jdk.tools.jaotc; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import jdk.tools.jaotc.collect.ClassSearch; +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.SearchFor; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; + +final class Options { + List files = new LinkedList<>(); + String osName; + String outputName = defaultOutputName(); + String methodList; + List sources = new ArrayList<>(); + String linkerpath = null; + SearchPath searchPath = new SearchPath(); + + /** + * We don't see scaling beyond 16 threads. + */ + private static final int COMPILER_THREADS = 16; + + int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); + + boolean ignoreClassLoadingErrors; + boolean exitOnError; + boolean info; + boolean verbose; + boolean debug; + boolean help; + boolean version; + boolean compileWithAssertions; + boolean tiered; + + private String defaultOutputName() { + osName = System.getProperty("os.name"); + String name = "unnamed."; + String ext; + + switch (osName) { + case "Linux": + case "SunOS": + ext = "so"; + break; + case "Mac OS X": + ext = "dylib"; + break; + default: + if (osName.startsWith("Windows")) { + ext = "dll"; + } else { + ext = "so"; + } + } + + return name + ext; + } + + static class BadArgs extends Exception { + private static final long serialVersionUID = 1L; + final String key; + final Object[] args; + boolean showUsage; + + BadArgs(String key, Object... args) { + super(MessageFormat.format(key, args)); + this.key = key; + this.args = args; + } + + BadArgs showUsage(boolean b) { + showUsage = b; + return this; + } + } + + abstract static class Option { + final String help; + final boolean hasArg; + final String[] aliases; + + Option(String help, boolean hasArg, String... aliases) { + this.help = help; + this.hasArg = hasArg; + this.aliases = aliases; + } + + boolean isHidden() { + return false; + } + + boolean matches(String opt) { + for (String a : aliases) { + if (a.equals(opt)) { + return true; + } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { + return true; + } + } + return false; + } + + boolean ignoreRest() { + return false; + } + + abstract void process(Main task, String opt, String arg) throws BadArgs; + } + + static Option[] recognizedOptions = {new Option(" --output Output file name", true, "--output") { + @Override + void process(Main task, String opt, String arg) { + String name = arg; + task.options.outputName = name; + } + }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); + } + }, new Option(" --jar List of jar files to compile", true, "--jar") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); + } + }, new Option(" --module List of modules to compile", true, "--module") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); + } + }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); + } + }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") { + @Override + void process(Main task, String opt, String arg) { + String[] elements = arg.split(":"); + task.options.searchPath.add(elements); + } + }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { + @Override + void process(Main task, String opt, String arg) { + task.options.methodList = arg; + } + }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { + @Override + void process(Main task, String opt, String arg) { + task.options.tiered = true; + } + }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { + @Override + void process(Main task, String opt, String arg) { + task.options.compileWithAssertions = true; + } + }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") { + @Override + void process(Main task, String opt, String arg) { + int threads = Integer.parseInt(arg); + final int available = Runtime.getRuntime().availableProcessors(); + if (threads <= 0) { + task.warning("invalid number of threads specified: {0}, using: {1}", threads, available); + threads = available; + } + if (threads > available) { + task.warning("too many threads specified: {0}, limiting to: {1}", threads, available); + } + task.options.threads = Integer.min(threads, available); + } + }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") { + @Override + void process(Main task, String opt, String arg) { + task.options.ignoreClassLoadingErrors = true; + } + }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") { + @Override + void process(Main task, String opt, String arg) { + task.options.exitOnError = true; + } + }, new Option(" --info Print information during compilation", false, "--info") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + } + }, new Option(" --verbose Print verbose information", false, "--verbose") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + task.options.verbose = true; + } + }, new Option(" --debug Print debug information", false, "--debug") { + @Override + void process(Main task, String opt, String arg) throws BadArgs { + task.options.info = true; + task.options.verbose = true; + task.options.debug = true; + } + }, new Option(" --help Print this usage message", false, "--help") { + @Override + void process(Main task, String opt, String arg) { + task.options.help = true; + } + }, new Option(" --version Version information", false, "--version") { + @Override + void process(Main task, String opt, String arg) { + task.options.version = true; + } + }, new Option(" --linker-path Full path to linker executable", true, "--linker-path") { + @Override + void process(Main task, String opt, String arg) { + task.options.linkerpath = arg; + } + }, new Option(" -J Pass directly to the runtime system", false, "-J") { + @Override + void process(Main task, String opt, String arg) { + } + }}; + + static void handleOptions(Main task, String[] args) throws BadArgs { + if (args.length == 0) { + task.options.help = true; + return; + } + + // Make checkstyle happy. + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + + if (arg.charAt(0) == '-') { + Option option = getOption(arg); + String param = null; + + if (option.hasArg) { + if (arg.startsWith("--") && arg.indexOf('=') > 0) { + param = arg.substring(arg.indexOf('=') + 1, arg.length()); + } else if (i + 1 < args.length) { + param = args[++i]; + } + + if (param == null || param.isEmpty() || param.charAt(0) == '-') { + throw new BadArgs("missing argument for option: {0}", arg).showUsage(true); + } + } + + option.process(task, arg, param); + + if (option.ignoreRest()) { + break; + } + } else { + task.options.files.add(new SearchFor(arg)); + } + } + } + + static Option getOption(String name) throws BadArgs { + for (Option o : recognizedOptions) { + if (o.matches(name)) { + return o; + } + } + throw new BadArgs("unknown option: {0}", name).showUsage(true); + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubDirectCallSiteRelocationSymbol.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -31,7 +31,7 @@ */ final class StubDirectCallSiteRelocationSymbol extends CallSiteRelocationSymbol { - public StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { + StubDirectCallSiteRelocationSymbol(CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { super(binaryContainer.getSymbol(callSiteRelocation.targetSymbol)); assert symbol != null && symbol.getBinding() == Binding.LOCAL : "Stub symbol must exist and must be LOCAL"; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/StubInformation.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package jdk.tools.jaotc; + +public final class StubInformation { + private int stubOffset; // the offset inside the code (text + stubOffset) + private int stubSize; // the stub size + private int dispatchJumpOffset; // offset after main dispatch jump instruction + private int resolveJumpOffset; // offset after jump instruction to runtime call resolution function. + private int resolveJumpStart; // offset of jump instruction to VM runtime call resolution function. + private int c2iJumpOffset; // offset after jump instruction to c2i adapter for static calls. + private int movOffset; // offset after move instruction which loads from got cell: + // - Method* for static call + // - Klass* for virtual call + + private boolean isVirtual; // virtual call stub + + // maybe add type of stub as well, right now we only have static stubs + + StubInformation(int stubOffset, boolean isVirtual) { + this.stubOffset = stubOffset; + this.isVirtual = isVirtual; + this.stubSize = -1; + this.movOffset = -1; + this.c2iJumpOffset = -1; + this.resolveJumpOffset = -1; + this.resolveJumpStart = -1; + this.dispatchJumpOffset = -1; + } + + int getOffset() { + return stubOffset; + } + + boolean isVirtual() { + return isVirtual; + } + + public void setSize(int stubSize) { + this.stubSize = stubSize; + } + + int getSize() { + return stubSize; + } + + public void setMovOffset(int movOffset) { + this.movOffset = movOffset + stubOffset; + } + + int getMovOffset() { + return movOffset; + } + + public void setC2IJumpOffset(int c2iJumpOffset) { + this.c2iJumpOffset = c2iJumpOffset + stubOffset; + } + + int getC2IJumpOffset() { + return c2iJumpOffset; + } + + public void setResolveJumpOffset(int resolveJumpOffset) { + this.resolveJumpOffset = resolveJumpOffset + stubOffset; + } + + int getResolveJumpOffset() { + return resolveJumpOffset; + } + + public void setResolveJumpStart(int resolveJumpStart) { + this.resolveJumpStart = resolveJumpStart + stubOffset; + } + + int getResolveJumpStart() { + return resolveJumpStart; + } + + public void setDispatchJumpOffset(int dispatchJumpOffset) { + this.dispatchJumpOffset = dispatchJumpOffset + stubOffset; + } + + int getDispatchJumpOffset() { + return dispatchJumpOffset; + } + + void verify() { + assert stubOffset > 0 : "incorrect stubOffset: " + stubOffset; + assert stubSize > 0 : "incorrect stubSize: " + stubSize; + assert movOffset > 0 : "incorrect movOffset: " + movOffset; + assert dispatchJumpOffset > 0 : "incorrect dispatchJumpOffset: " + dispatchJumpOffset; + assert resolveJumpStart > 0 : "incorrect resolveJumpStart: " + resolveJumpStart; + assert resolveJumpOffset > 0 : "incorrect resolveJumpOffset: " + resolveJumpOffset; + if (!isVirtual) { + assert c2iJumpOffset > 0 : "incorrect c2iJumpOffset: " + c2iJumpOffset; + } + } +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Timer.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, 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. + */ + +package jdk.tools.jaotc; + +final class Timer implements AutoCloseable { + + private final Main main; + private final long start; + + Timer(Main main, String message) { + this.main = main; + start = System.currentTimeMillis(); + main.printer.printInfo(message); + } + + public void close() { + final long end = System.currentTimeMillis(); + main.printer.printlnInfo(" (" + (end - start) + " ms)"); + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64ELFMacroAssembler.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -27,7 +27,7 @@ import static jdk.vm.ci.amd64.AMD64.rbx; import static jdk.vm.ci.amd64.AMD64.rip; -import jdk.tools.jaotc.CompiledMethodInfo.StubInformation; +import jdk.tools.jaotc.StubInformation; import jdk.tools.jaotc.ELFMacroAssembler; import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/amd64/AMD64InstructionDecoder.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -35,43 +35,43 @@ private static class Prefix { // segment overrides - public static final int CSSegment = 0x2e; - public static final int SSSegment = 0x36; - public static final int DSSegment = 0x3e; - public static final int ESSegment = 0x26; - public static final int FSSegment = 0x64; - public static final int GSSegment = 0x65; - public static final int REX = 0x40; - public static final int REXB = 0x41; - public static final int REXX = 0x42; - public static final int REXXB = 0x43; - public static final int REXR = 0x44; - public static final int REXRB = 0x45; - public static final int REXRX = 0x46; - public static final int REXRXB = 0x47; - public static final int REXW = 0x48; - public static final int REXWB = 0x49; - public static final int REXWX = 0x4A; - public static final int REXWXB = 0x4B; - public static final int REXWR = 0x4C; - public static final int REXWRB = 0x4D; - public static final int REXWRX = 0x4E; - public static final int REXWRXB = 0x4F; - public static final int VEX_3BYTES = 0xC4; - public static final int VEX_2BYTES = 0xC5; + static final int CSSegment = 0x2e; + static final int SSSegment = 0x36; + static final int DSSegment = 0x3e; + static final int ESSegment = 0x26; + static final int FSSegment = 0x64; + static final int GSSegment = 0x65; + static final int REX = 0x40; + static final int REXB = 0x41; + static final int REXX = 0x42; + static final int REXXB = 0x43; + static final int REXR = 0x44; + static final int REXRB = 0x45; + static final int REXRX = 0x46; + static final int REXRXB = 0x47; + static final int REXW = 0x48; + static final int REXWB = 0x49; + static final int REXWX = 0x4A; + static final int REXWXB = 0x4B; + static final int REXWR = 0x4C; + static final int REXWRB = 0x4D; + static final int REXWRX = 0x4E; + static final int REXWRXB = 0x4F; + static final int VEX_3BYTES = 0xC4; + static final int VEX_2BYTES = 0xC5; } - public static class VexPrefix { - public static final int VEX_R = 0x80; - public static final int VEX_W = 0x80; + private static class VexPrefix { + static final int VEX_R = 0x80; + static final int VEX_W = 0x80; } - public static class VexOpcode { - public static final int VEX_OPCODE_NONE = 0x0; - public static final int VEX_OPCODE_0F = 0x1; - public static final int VEX_OPCODE_0F_38 = 0x2; - public static final int VEX_OPCODE_0F_3A = 0x3; - public static final int VEX_OPCODE_MASK = 0x1F; + private static class VexOpcode { + static final int VEX_OPCODE_NONE = 0x0; + static final int VEX_OPCODE_0F = 0x1; + static final int VEX_OPCODE_0F_38 = 0x2; + static final int VEX_OPCODE_0F_3A = 0x3; + static final int VEX_OPCODE_MASK = 0x1F; } public AMD64InstructionDecoder(TargetDescription target) { @@ -112,7 +112,7 @@ againAfterPrefix = false; switch (0xFF & code[ip++]) { - // These convenience macros generate groups of "case" labels for the switch. + // These convenience macros generate groups of "case" labels for the switch. case Prefix.CSSegment: case Prefix.SSSegment: @@ -446,7 +446,7 @@ tailSize = 1; // the imm8 break; default: - ; // no imm8 + break; // no imm8 } break; case VexOpcode.VEX_OPCODE_0F_3A: diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; import jdk.tools.jaotc.LoadedClass; @@ -27,8 +28,8 @@ import java.util.ArrayList; import java.util.List; -public class ClassSearch { - private List providers = new ArrayList<>(); +public final class ClassSearch { + private final List providers = new ArrayList<>(); public void addProvider(SourceProvider provider) { providers.add(provider); @@ -50,7 +51,7 @@ return loaded; } - private LoadedClass loadClass(String name, ClassLoader loader) { + private static LoadedClass loadClass(String name, ClassLoader loader) { try { Class clzz = loader.loadClass(name); return new LoadedClass(name, clzz); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; import java.nio.file.Path; @@ -32,17 +33,17 @@ } static String stripRoot(Path path) { - if (path.getRoot() != null) { - String root = path.getRoot().toString(); - String filename = path.toString().substring(root.length()); - String separator = path.getFileSystem().getSeparator(); - while (filename.startsWith(separator)) { - filename = filename.substring(separator.length()); + if (path.getRoot() != null) { + String root = path.getRoot().toString(); + String filename = path.toString().substring(root.length()); + String separator = path.getFileSystem().getSeparator(); + while (filename.startsWith(separator)) { + filename = filename.substring(separator.length()); + } + return filename; } - return filename; - } - return path.toString(); + return path.toString(); } static String makeClassName(Path path) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; import java.io.IOException; @@ -28,7 +29,7 @@ import java.util.HashMap; public class FileSupport { - public boolean exists(Path path) { + public boolean exists(Path path) { return Files.exists(path); } @@ -36,7 +37,7 @@ return Files.isDirectory(path); } - private FileSystem makeJarFileSystem(Path path) { + private static FileSystem makeJarFileSystem(Path path) { try { return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>()); } catch (IOException e) { @@ -44,10 +45,10 @@ } } - private URI makeJarFileURI(Path path) { + private static URI makeJarFileURI(Path path) { try { String name = path.toAbsolutePath().toString(); - name = name.replace('\\','/'); + name = name.replace('\\', '/'); return new URI("jar:file:///" + name + "!/"); } catch (URISyntaxException e) { throw new InternalError(e); @@ -66,8 +67,8 @@ return URLClassLoader.newInstance(buildUrls(path)); } - private URL[] buildUrls(Path path) throws MalformedURLException { - return new URL[] { path.toUri().toURL() }; + private static URL[] buildUrls(Path path) throws MalformedURLException { + return new URL[]{path.toUri().toURL()}; } public Path getJarFileSystemRoot(Path jarFile) { @@ -80,7 +81,7 @@ } public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException { - DirectoryStream paths = fileSystem.provider().newDirectoryStream(root,null); + DirectoryStream paths = fileSystem.provider().newDirectoryStream(root, null); for (Path entry : paths) { Path relative = root.relativize(entry); if (relative.equals(path)) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; import java.io.IOException; @@ -33,7 +34,7 @@ /** * {@link FileVisitor} implementation to find class files recursively. */ -public class FileSystemFinder extends SimpleFileVisitor implements Iterable { +public final class FileSystemFinder extends SimpleFileVisitor implements Iterable { private final ArrayList fileNames = new ArrayList<>(); private final PathMatcher filter; @@ -68,7 +69,6 @@ return CONTINUE; } - @Override public Iterator iterator() { return fileNames.iterator(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,9 +20,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; -public class SearchFor { +public final class SearchFor { private final String name; private final String type; @@ -35,15 +36,15 @@ this.type = type; } - public boolean isUnknown() { + boolean isUnknown() { return "".equals(type); } - public String getType() { + String getType() { return this.type; } - public String getName() { + String getName() { return this.name; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; import java.nio.file.FileSystem; @@ -84,4 +85,3 @@ } } } - diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect; public interface SourceProvider { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,17 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.classname; import jdk.tools.jaotc.collect.ClassSource; import java.util.function.BiConsumer; -public class ClassNameSource implements ClassSource { +public final class ClassNameSource implements ClassSource { private final String name; private final ClassLoader classLoader; - public ClassNameSource(String name, ClassLoader classLoader) { + ClassNameSource(String name, ClassLoader classLoader) { this.name = name; this.classLoader = classLoader; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.classname; import jdk.tools.jaotc.collect.ClassSource; @@ -30,7 +31,7 @@ import java.nio.file.Path; import java.nio.file.Paths; -public class ClassNameSourceProvider implements SourceProvider { +public final class ClassNameSourceProvider implements SourceProvider { public final static String TYPE = "class"; private final ClassLoader classLoader; @@ -46,7 +47,8 @@ } @Override - public ClassSource findSource(String name, SearchPath searchPath) { + public ClassSource findSource(String name0, SearchPath searchPath) { + String name = name0; Path path = Paths.get(name); if (ClassSource.pathIsClassFile(path)) { name = ClassSource.makeClassName(path); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.directory; import jdk.tools.jaotc.collect.ClassSource; @@ -28,11 +29,11 @@ import java.nio.file.Path; import java.util.function.BiConsumer; -public class DirectorySource implements ClassSource { +public final class DirectorySource implements ClassSource { private final Path directoryPath; private final ClassLoader classLoader; - public DirectorySource(Path directoryPath, ClassLoader classLoader) { + DirectorySource(Path directoryPath, ClassLoader classLoader) { this.directoryPath = directoryPath; this.classLoader = classLoader; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.directory; import jdk.tools.jaotc.collect.ClassSource; @@ -32,7 +33,7 @@ import java.nio.file.FileSystems; import java.nio.file.Path; -public class DirectorySourceProvider implements SourceProvider { +public final class DirectorySourceProvider implements SourceProvider { private final FileSupport fileSupport; private final FileSystem fileSystem; public final static String TYPE = "directory"; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.jar; import jdk.tools.jaotc.collect.ClassSource; @@ -28,18 +29,18 @@ import java.nio.file.Path; import java.util.function.BiConsumer; -public class JarFileSource implements ClassSource { +public final class JarFileSource implements ClassSource { private final Path jarFile; private final Path jarRootPath; private final ClassLoader classLoader; - - public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) { + JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) { this.jarFile = jarFile; this.jarRootPath = jarRootPath; this.classLoader = classLoader; } + @Override public void eachClass(BiConsumer consumer) { FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.jar; import jdk.tools.jaotc.collect.ClassSource; @@ -33,7 +34,7 @@ import java.nio.file.Path; import java.nio.file.ProviderNotFoundException; -public class JarSourceProvider implements SourceProvider { +public final class JarSourceProvider implements SourceProvider { private final FileSystem fileSystem; private final FileSupport fileSupport; public final static String TYPE = "jar"; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.module; import jdk.tools.jaotc.collect.ClassSource; @@ -28,15 +29,19 @@ import java.nio.file.Path; import java.util.function.BiConsumer; -public class ModuleSource implements ClassSource { +public final class ModuleSource implements ClassSource { private final Path modulePath; private final ClassLoader classLoader; - public ModuleSource(Path modulePath, ClassLoader classLoader) { + ModuleSource(Path modulePath, ClassLoader classLoader) { this.modulePath = modulePath; this.classLoader = classLoader; } + public Path getModulePath() { + return modulePath; + } + @Override public void eachClass(BiConsumer consumer) { FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile); @@ -46,10 +51,6 @@ } } - public Path getModulePath() { - return modulePath; - } - @Override public String toString() { return "module:" + modulePath.toString(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.tools.jaotc.collect.module; import jdk.tools.jaotc.collect.ClassSource; @@ -33,7 +34,7 @@ import java.nio.file.FileSystems; import java.nio.file.Path; -public class ModuleSourceProvider implements SourceProvider { +public final class ModuleSourceProvider implements SourceProvider { private final FileSystem fileSystem; private final ClassLoader classLoader; private final FileSupport fileSupport; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/NativeOrderOutputStream.java Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -29,7 +29,7 @@ import java.util.ArrayList; import java.util.List; -public class NativeOrderOutputStream { +public final class NativeOrderOutputStream { private final PatchableByteOutputStream os = new PatchableByteOutputStream(); private final byte[] backingArray = new byte[8]; private final ByteBuffer buffer; @@ -181,7 +181,7 @@ private static class PatchableByteOutputStream extends ByteArrayOutputStream { public void writeAt(byte[] data, int length, int position) { - long end = (long)position + (long)length; + long end = (long) position + (long) length; if (buf.length < end) { throw new IllegalArgumentException("Array not properly sized"); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/utils/Timer.java Sun Sep 03 19:31:11 2017 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.tools.jaotc.utils; - -import jdk.tools.jaotc.Main; - -public class Timer implements AutoCloseable { - - private final Main main; - private final long start; - - public Timer(Main main, String message) { - this.main = main; - start = System.currentTimeMillis(); - main.printInfo(message); - } - - public void close() { - final long end = System.currentTimeMillis(); - main.printlnInfo(" (" + (end - start) + " ms)"); - } - -} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java --- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Tue Sep 05 10:09:44 2017 -0700 @@ -153,9 +153,9 @@ * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will * either return a {@link ResolvedJavaType} or throw an exception * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false} - * @throws LinkageError if {@code resolve == true} and the resolution failed + * @throws ClassNotFoundException if {@code resolve == true} and the resolution failed */ - native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve); + native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve) throws ClassNotFoundException; /** * Resolves the entry at index {@code cpi} in {@code constantPool} to an object. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java --- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Tue Sep 05 10:09:44 2017 -0700 @@ -367,13 +367,17 @@ // Resolve non-primitive types in the VM. HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; - final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + try { + final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); - if (klass == null) { - assert resolve == false; - return HotSpotUnresolvedJavaType.create(this, name); + if (klass == null) { + assert resolve == false; + return HotSpotUnresolvedJavaType.create(this, name); + } + return klass; + } catch (ClassNotFoundException e) { + throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); } - return klass; } public JVMCIBackend getHostJVMCIBackend() { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java --- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java Tue Sep 05 10:09:44 2017 -0700 @@ -45,7 +45,9 @@ public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) { this.runtime = runtime; - assert signature.length() > 0; + if (signature.length() == 0) { + throw new IllegalArgumentException("Signature cannot be empty"); + } this.originalString = signature; if (signature.charAt(0) == '(') { @@ -59,9 +61,11 @@ cur++; int nextCur = parseSignature(signature, cur); returnType = signature.substring(cur, nextCur); - assert nextCur == signature.length(); + if (nextCur != signature.length()) { + throw new IllegalArgumentException("Extra characters at end of signature: " + signature); + } } else { - returnType = null; + throw new IllegalArgumentException("Signature must start with a '(': " + signature); } } @@ -81,33 +85,41 @@ } private static int parseSignature(String signature, int start) { - int cur = start; - char first; - do { - first = signature.charAt(cur++); - } while (first == '['); - - switch (first) { - case 'L': - while (signature.charAt(cur) != ';') { - cur++; - } + try { + int cur = start; + char first; + do { + first = signature.charAt(cur); cur++; - break; - case 'V': - case 'I': - case 'B': - case 'C': - case 'D': - case 'F': - case 'J': - case 'S': - case 'Z': - break; - default: - throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature); + } while (first == '['); + + switch (first) { + case 'L': + while (signature.charAt(cur) != ';') { + if (signature.charAt(cur) == '.') { + throw new IllegalArgumentException("Class name in signature contains '.' at index " + cur + ": " + signature); + } + cur++; + } + cur++; + break; + case 'V': + case 'I': + case 'B': + case 'C': + case 'D': + case 'F': + case 'J': + case 'S': + case 'Z': + break; + default: + throw new IllegalArgumentException("Invalid character '" + signature.charAt(cur - 1) + "' at index " + (cur - 1) + " in signature: " + signature); + } + return cur; + } catch (StringIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Truncated signature: " + signature); } - return cur; } @Override diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java --- a/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -83,8 +83,9 @@ /** * Parses a * method - * descriptor into a {@link Signature}. The behavior of this method is undefined if the - * method descriptor is not well formed. + * descriptor into a {@link Signature}. + * + * @throws IllegalArgumentException if the method descriptor is not well formed */ Signature parseMethodDescriptor(String methodDescriptor); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java Tue Sep 05 10:09:44 2017 -0700 @@ -158,7 +158,7 @@ } break; default: - throw GraalError.shouldNotReachHere(); + throw GraalError.shouldNotReachHere(input.getPlatformKind().toString()); } return result; } @@ -451,7 +451,7 @@ protected Value emitZeroExtendMemory(AMD64Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) { // Issue a zero extending load of the proper bit size and set the result to // the proper kind. - Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD)); + Variable result = getLIRGen().newVariable(LIRKind.value(resultBits <= 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD)); switch (memoryKind) { case BYTE: getLIRGen().append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state)); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,16 +25,26 @@ import org.graalvm.compiler.debug.GraalError; public enum FloatConvert { - F2I, - D2I, - F2L, - D2L, - I2F, - L2F, - D2F, - I2D, - L2D, - F2D; + F2I(FloatConvertCategory.FloatingPointToInteger), + D2I(FloatConvertCategory.FloatingPointToInteger), + F2L(FloatConvertCategory.FloatingPointToInteger), + D2L(FloatConvertCategory.FloatingPointToInteger), + I2F(FloatConvertCategory.IntegerToFloatingPoint), + L2F(FloatConvertCategory.IntegerToFloatingPoint), + D2F(FloatConvertCategory.FloatingPointToFloatingPoint), + I2D(FloatConvertCategory.IntegerToFloatingPoint), + L2D(FloatConvertCategory.IntegerToFloatingPoint), + F2D(FloatConvertCategory.FloatingPointToFloatingPoint); + + private FloatConvertCategory category; + + FloatConvert(FloatConvertCategory category) { + this.category = category; + } + + public FloatConvertCategory getCategory() { + return category; + } public FloatConvert reverse() { switch (this) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvertCategory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvertCategory.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,29 @@ +/* + * 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. + */ +package org.graalvm.compiler.core.common.calc; + +public enum FloatConvertCategory { + FloatingPointToInteger, + IntegerToFloatingPoint, + FloatingPointToFloatingPoint; +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Tue Sep 05 10:09:44 2017 -0700 @@ -33,9 +33,11 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.MulHigh; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.UMulHigh; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend; @@ -62,6 +64,8 @@ private final BinaryOp sub; private final BinaryOp mul; + private final BinaryOp mulHigh; + private final BinaryOp umulHigh; private final BinaryOp
div; private final BinaryOp rem; @@ -92,7 +96,7 @@ } } - public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); public interface ArithmeticOpWrapper { @@ -121,6 +125,8 @@ BinaryOp sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub()); BinaryOp mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul()); + BinaryOp mulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMulHigh()); + BinaryOp umulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getUMulHigh()); BinaryOp
div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv()); BinaryOp rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem()); @@ -141,16 +147,18 @@ IntegerConvertOp narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow()); FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new); - return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert); + return new ArithmeticOpTable(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert); } - protected ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp
div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, - BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, IntegerConvertOp zeroExtend, - IntegerConvertOp signExtend, IntegerConvertOp narrow, FloatConvertOp... floatConvert) { + protected ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp mulHigh, BinaryOp umulHigh, BinaryOp
div, BinaryOp rem, + UnaryOp not, BinaryOp and, BinaryOp or, BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, + IntegerConvertOp zeroExtend, IntegerConvertOp signExtend, IntegerConvertOp narrow, FloatConvertOp... floatConvert) { this.neg = neg; this.add = add; this.sub = sub; this.mul = mul; + this.mulHigh = mulHigh; + this.umulHigh = umulHigh; this.div = div; this.rem = rem; this.not = not; @@ -207,6 +215,20 @@ } /** + * Describes a signed operation that multiples the upper 32-bits of two long values. + */ + public BinaryOp getMulHigh() { + return mulHigh; + } + + /** + * Describes an unsigned operation that multiples the upper 32-bits of two long values. + */ + public BinaryOp getUMulHigh() { + return umulHigh; + } + + /** * Describes the division operation. */ public BinaryOp
getDiv() { @@ -321,6 +343,8 @@ Objects.equals(add, that.add) && Objects.equals(sub, that.sub) && Objects.equals(mul, that.mul) && + Objects.equals(mulHigh, that.mulHigh) && + Objects.equals(umulHigh, that.umulHigh) && Objects.equals(div, that.div) && Objects.equals(rem, that.rem) && Objects.equals(not, that.not) && @@ -360,8 +384,8 @@ @Override public String toString() { - return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" + - toString(floatConvert) + "]]"; + return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + + ",floatConvert[" + toString(floatConvert) + "]]"; } public abstract static class Op { @@ -479,6 +503,20 @@ } } + public abstract static class MulHigh extends BinaryOp { + + protected MulHigh(boolean associative, boolean commutative) { + super("*H", associative, commutative); + } + } + + public abstract static class UMulHigh extends BinaryOp { + + protected UMulHigh(boolean associative, boolean commutative) { + super("|*H|", associative, commutative); + } + } + public abstract static class Div extends BinaryOp
{ protected Div(boolean associative, boolean commutative) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Tue Sep 05 10:09:44 2017 -0700 @@ -302,7 +302,7 @@ return null; } - private static final ArithmeticOpTable OPS = new ArithmeticOpTable( + public static final ArithmeticOpTable OPS = new ArithmeticOpTable( new UnaryOp.Neg() { @@ -437,6 +437,10 @@ } }, + null, + + null, + new BinaryOp.Div(false, false) { @Override diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Tue Sep 05 10:09:44 2017 -0700 @@ -858,6 +858,164 @@ } }, + new BinaryOp.MulHigh(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), multiplyHigh(a.asLong(), b.asLong(), a.getJavaKind())); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + JavaKind javaKind = a.getStackKind(); + + assert a.getBits() == b.getBits(); + assert javaKind == b.getStackKind(); + assert (javaKind == JavaKind.Int || javaKind == JavaKind.Long); + + if (a.isEmpty() || b.isEmpty()) { + return a.empty(); + } else if (a.isUnrestricted() || b.isUnrestricted()) { + return a.unrestricted(); + } + + long[] xExtremes = {a.lowerBound(), a.upperBound()}; + long[] yExtremes = {b.lowerBound(), b.upperBound()}; + long min = Long.MAX_VALUE; + long max = Long.MIN_VALUE; + for (long x : xExtremes) { + for (long y : yExtremes) { + long result = multiplyHigh(x, y, javaKind); + min = Math.min(min, result); + max = Math.max(max, result); + } + } + return StampFactory.forInteger(javaKind, min, max); + } + + @Override + public boolean isNeutral(Constant value) { + return false; + } + + private long multiplyHigh(long x, long y, JavaKind javaKind) { + if (javaKind == JavaKind.Int) { + return (x * y) >> 32; + } else { + assert javaKind == JavaKind.Long; + long x0 = x & 0xFFFFFFFFL; + long x1 = x >> 32; + + long y0 = y & 0xFFFFFFFFL; + long y1 = y >> 32; + + long z0 = x0 * y0; + long t = x1 * y0 + (z0 >>> 32); + long z1 = t & 0xFFFFFFFFL; + long z2 = t >> 32; + z1 += x0 * y1; + + return x1 * y1 + z2 + (z1 >> 32); + } + } + }, + + new BinaryOp.UMulHigh(true, true) { + + @Override + public Constant foldConstant(Constant const1, Constant const2) { + PrimitiveConstant a = (PrimitiveConstant) const1; + PrimitiveConstant b = (PrimitiveConstant) const2; + assert a.getJavaKind() == b.getJavaKind(); + return JavaConstant.forIntegerKind(a.getJavaKind(), multiplyHighUnsigned(a.asLong(), b.asLong(), a.getJavaKind())); + } + + @Override + public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { + IntegerStamp a = (IntegerStamp) stamp1; + IntegerStamp b = (IntegerStamp) stamp2; + JavaKind javaKind = a.getStackKind(); + + assert a.getBits() == b.getBits(); + assert javaKind == b.getStackKind(); + assert (javaKind == JavaKind.Int || javaKind == JavaKind.Long); + + if (a.isEmpty() || b.isEmpty()) { + return a.empty(); + } else if (a.isUnrestricted() || b.isUnrestricted()) { + return a.unrestricted(); + } + + // Note that the minima and maxima are calculated using signed min/max + // functions, while the values themselves are unsigned. + long[] xExtremes = getUnsignedExtremes(a); + long[] yExtremes = getUnsignedExtremes(b); + long min = Long.MAX_VALUE; + long max = Long.MIN_VALUE; + for (long x : xExtremes) { + for (long y : yExtremes) { + long result = multiplyHighUnsigned(x, y, javaKind); + min = Math.min(min, result); + max = Math.max(max, result); + } + } + + // if min is negative, then the value can reach into the unsigned range + if (min == max || min >= 0) { + return StampFactory.forInteger(javaKind, min, max); + } else { + return StampFactory.forKind(javaKind); + } + } + + @Override + public boolean isNeutral(Constant value) { + return false; + } + + private long[] getUnsignedExtremes(IntegerStamp stamp) { + if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) { + /* + * If -1 and 0 are both in the signed range, then we can't say + * anything about the unsigned range, so we have to return [0, + * MAX_UNSIGNED]. + */ + return new long[]{0, -1L}; + } else { + return new long[]{stamp.lowerBound(), stamp.upperBound()}; + } + } + + private long multiplyHighUnsigned(long x, long y, JavaKind javaKind) { + if (javaKind == JavaKind.Int) { + long xl = x & 0xFFFFFFFFL; + long yl = y & 0xFFFFFFFFL; + long r = xl * yl; + return (int) (r >>> 32); + } else { + assert javaKind == JavaKind.Long; + long x0 = x & 0xFFFFFFFFL; + long x1 = x >>> 32; + + long y0 = y & 0xFFFFFFFFL; + long y1 = y >>> 32; + + long z0 = x0 * y0; + long t = x1 * y0 + (z0 >>> 32); + long z1 = t & 0xFFFFFFFFL; + long z2 = t >>> 32; + z1 += x0 * y1; + + return x1 * y1 + z2 + (z1 >>> 32); + } + } + }, + new BinaryOp.Div(true, false) { @Override @@ -1046,10 +1204,14 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { IntegerStamp value = (IntegerStamp) stamp; int bits = value.getBits(); - long defaultMask = CodeUtil.mask(bits); - if (value.upMask() == 0) { + if (value.isEmpty()) { + return value; + } else if (shift.isEmpty()) { + return StampFactory.forInteger(bits).empty(); + } else if (value.upMask() == 0) { return value; } + int shiftMask = getShiftAmountMask(stamp); int shiftBits = Integer.bitCount(shiftMask); if (shift.lowerBound() == shift.upperBound()) { @@ -1068,6 +1230,7 @@ } } if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) { + long defaultMask = CodeUtil.mask(bits); long downMask = defaultMask; long upMask = 0; for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) { @@ -1109,7 +1272,11 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { IntegerStamp value = (IntegerStamp) stamp; int bits = value.getBits(); - if (shift.lowerBound() == shift.upperBound()) { + if (value.isEmpty()) { + return value; + } else if (shift.isEmpty()) { + return StampFactory.forInteger(bits).empty(); + } else if (shift.lowerBound() == shift.upperBound()) { long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp); if (shiftCount == 0) { return stamp; @@ -1153,6 +1320,12 @@ public Stamp foldStamp(Stamp stamp, IntegerStamp shift) { IntegerStamp value = (IntegerStamp) stamp; int bits = value.getBits(); + if (value.isEmpty()) { + return value; + } else if (shift.isEmpty()) { + return StampFactory.forInteger(bits).empty(); + } + if (shift.lowerBound() == shift.upperBound()) { long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp); if (shiftCount == 0) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -46,6 +46,16 @@ public static double SideEffectD; public static double SideEffectL; + private static final long byteArrayBaseOffset; + private static final long intArrayBaseOffset; + private static final long longArrayBaseOffset; + + static { + byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); + intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class); + longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class); + } + public static long test1Snippet(double a) { final Object m = Memory; if (a > 0) { @@ -130,4 +140,76 @@ Assert.assertEquals(writes, graph.getNodes().filter(WriteNode.class).count()); } + public static int testWriteIntToByteArraySnippet() { + byte[] array = new byte[4]; + UNSAFE.putInt(array, byteArrayBaseOffset, 0x01020304); + return array[0]; + } + + @Test + public void testWriteIntToByteArray() { + test("testWriteIntToByteArraySnippet"); + } + + public static byte testWriteSignedExtendedByteToByteArraySnippet(byte b) { + byte[] array = new byte[4]; + array[0] = 0x01; + array[1] = 0x02; + array[2] = 0x03; + array[3] = 0x04; + UNSAFE.putInt(array, byteArrayBaseOffset, b); + return array[3]; + } + + @Test + public void testWriteSignedExtendedByteToByteArray() { + test("testWriteSignedExtendedByteToByteArraySnippet", (byte) 0); + } + + public static int testWriteLongToIntArraySnippet() { + int[] array = new int[2]; + UNSAFE.putLong(array, intArrayBaseOffset, 0x0102030405060708L); + return array[0]; + } + + @Test + public void testWriteLongToIntArray() { + test("testWriteLongToIntArraySnippet"); + } + + public static int testWriteByteToIntArraySnippet() { + int[] array = new int[1]; + array[0] = 0x01020304; + UNSAFE.putByte(array, intArrayBaseOffset, (byte) 0x05); + return array[0]; + } + + @Test + public void testWriteByteToIntArray() { + test("testWriteByteToIntArraySnippet"); + } + + public static long testWriteIntToLongArraySnippet() { + long[] array = new long[1]; + array[0] = 0x0102030405060708L; + UNSAFE.putInt(array, longArrayBaseOffset, 0x04030201); + return array[0]; + } + + @Test + public void testWriteIntToLongArray() { + test("testWriteIntToLongArraySnippet"); + } + + public static float testWriteFloatToIntArraySnippet() { + float[] array = new float[1]; + UNSAFE.putInt(array, intArrayBaseOffset, Float.floatToRawIntBits(0.5f)); + return array[0]; + } + + @Test + public void testWriteFloatToIntArray() { + test("testWriteFloatToIntArraySnippet"); + } + } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Tue Sep 05 10:09:44 2017 -0700 @@ -38,10 +38,6 @@ private static final long fieldOffset1; private static final long fieldOffset2; - private static final long byteArrayBaseOffset; - private static final long intArrayBaseOffset; - private static final long longArrayBaseOffset; - static { try { long localFieldOffset1 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("x")); @@ -55,9 +51,6 @@ fieldOffset2 = UNSAFE.objectFieldOffset(TestClassInt.class.getField("z")); } assert fieldOffset2 == fieldOffset1 + 4; - byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); - intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class); - longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class); } catch (Exception e) { throw new RuntimeException(e); } @@ -203,76 +196,4 @@ return x; } - public static int testWriteIntToByteArraySnippet() { - byte[] array = new byte[4]; - UNSAFE.putInt(array, byteArrayBaseOffset, 0x01020304); - return array[0]; - } - - @Test - public void testWriteIntToByteArray() { - test("testWriteIntToByteArraySnippet"); - } - - public static byte testWriteSignedExtendedByteToByteArraySnippet(byte b) { - byte[] array = new byte[4]; - array[0] = 0x01; - array[1] = 0x02; - array[2] = 0x03; - array[3] = 0x04; - UNSAFE.putInt(array, byteArrayBaseOffset, b); - return array[3]; - } - - @Test - public void testWriteSignedExtendedByteToByteArray() { - test("testWriteSignedExtendedByteToByteArraySnippet", (byte) 0); - } - - public static int testWriteLongToIntArraySnippet() { - int[] array = new int[2]; - UNSAFE.putLong(array, intArrayBaseOffset, 0x0102030405060708L); - return array[0]; - } - - @Test - public void testWriteLongToIntArray() { - test("testWriteLongToIntArraySnippet"); - } - - public static int testWriteByteToIntArraySnippet() { - int[] array = new int[1]; - array[0] = 0x01020304; - UNSAFE.putByte(array, intArrayBaseOffset, (byte) 0x05); - return array[0]; - } - - @Test - public void testWriteByteToIntArray() { - test("testWriteByteToIntArraySnippet"); - } - - public static long testWriteIntToLongArraySnippet() { - long[] array = new long[1]; - array[0] = 0x0102030405060708L; - UNSAFE.putInt(array, longArrayBaseOffset, 0x04030201); - return array[0]; - } - - @Test - public void testWriteIntToLongArray() { - test("testWriteIntToLongArraySnippet"); - } - - public static float testWriteFloatToIntArraySnippet() { - float[] array = new float[1]; - UNSAFE.putInt(array, intArrayBaseOffset, Float.floatToRawIntBits(0.5f)); - return array[0]; - } - - @Test - public void testWriteFloatToIntArray() { - test("testWriteFloatToIntArraySnippet"); - } - } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java Tue Sep 05 10:09:44 2017 -0700 @@ -58,6 +58,11 @@ */ public static CompilationPrinter begin(OptionValues options, CompilationIdentifier id, JavaMethod method, int entryBCI) { if (PrintCompilation.getValue(options) && !TTY.isSuppressed()) { + try { + Class.forName("java.lang.management.ManagementFactory"); + } catch (ClassNotFoundException ex) { + throw new IllegalArgumentException("PrintCompilation option requires java.management module"); + } return new CompilationPrinter(id, method, entryBCI); } return DISABLED; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java Tue Sep 05 10:09:44 2017 -0700 @@ -82,26 +82,6 @@ */ ExitVM; - static ValueHelp HELP = new ValueHelp(); - - static class ValueHelp implements EnumOptionKey.ValueHelp { - @Override - public String getHelp(Object value) { - ExceptionAction action = (ExceptionAction) value; - switch (action) { - case Silent: - return action + ": Print nothing to the console."; - case Print: - return action + ": Print a stack trace to the console."; - case Diagnose: - return action + ": Retry the compilation with extra diagnostics."; - case ExitVM: - return action + ": Same as " + Diagnose + " except that the VM process exits after retrying."; - } - return null; - } - } - /** * Gets the action that is one level less verbose than this action, bottoming out at the * least verbose action. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Tue Sep 05 10:09:44 2017 -0700 @@ -36,13 +36,15 @@ // @formatter:off @Option(help = "Print an informational line to the console for each completed compilation.", type = OptionType.Debug) public static final OptionKey PrintCompilation = new OptionKey<>(false); - @Option(help = "Pattern (see MethodFilter for format) for method that will trigger an exception when compiled. " + - "This option exists to test handling compilation crashes gracefully.", type = OptionType.Debug) + @Option(help = "Pattern for method(s) that will trigger an exception when compiled. " + + "This option exists to test handling compilation crashes gracefully. " + + "See the MethodFilter option for the pattern syntax. ", type = OptionType.Debug) public static final OptionKey CrashAt = new OptionKey<>(null); - @Option(help = "The action to take when compilation fails with a non-bailout exception.", type = OptionType.User) - public static final EnumOptionKey CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose, ExceptionAction.HELP); - @Option(help = "The action to take when compilation fails with a bailout exception.", type = OptionType.User) - public static final EnumOptionKey CompilationBailoutAction = new EnumOptionKey<>(ExceptionAction.Silent, ExceptionAction.HELP); + @Option(help = "file:doc-files/CompilationBailoutActionHelp.txt", type = OptionType.User) + public static final EnumOptionKey CompilationBailoutAction = new EnumOptionKey<>(ExceptionAction.Silent); + @Option(help = "Specifies the action to take when compilation fails with a bailout exception. " + + "The accepted values are the same as for CompilationBailoutAction.", type = OptionType.User) + public static final EnumOptionKey CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose); @Option(help = "The maximum number of compilation failures or bailouts to handle with the action specified " + "by CompilationFailureAction or CompilationBailoutAction before changing to a less verbose action.", type = OptionType.User) public static final OptionKey MaxCompilationProblemsPerAction = new OptionKey<>(5); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/doc-files/CompilationBailoutActionHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/doc-files/CompilationBailoutActionHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,6 @@ +Specifies the action to take when compilation fails with a bailout exception. +The accepted values are: + Silent - Print nothing to the console. + Print - Print a stack trace to the console. + Diagnose - Retry the compilation with extra diagnostics. + ExitVM - Same as Diagnose except that the VM process exits after retrying. \ No newline at end of file diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Tue Sep 05 10:09:44 2017 -0700 @@ -198,9 +198,22 @@ private Immutable(OptionValues options) { this.options = options; + String timeValue = Time.getValue(options); + String trackMemUseValue = TrackMemUse.getValue(options); this.unscopedCounters = parseUnscopedMetricSpec(Counters.getValue(options), "".equals(Count.getValue(options)), false); - this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(Time.getValue(options)), true); - this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(TrackMemUse.getValue(options)), true); + this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(timeValue), true); + this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(trackMemUseValue), true); + + if (unscopedTimers != null || + unscopedMemUseTrackers != null || + timeValue != null || + trackMemUseValue != null) { + try { + Class.forName("java.lang.management.ManagementFactory"); + } catch (ClassNotFoundException ex) { + throw new IllegalArgumentException("Time, Timers, MemUseTrackers and TrackMemUse options require java.management module"); + } + } this.scopesEnabled = DumpOnError.getValue(options) || Dump.getValue(options) != null || diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java Tue Sep 05 10:09:44 2017 -0700 @@ -28,8 +28,11 @@ import org.graalvm.compiler.debug.DebugContext.Scope; /** - * Implements the filter specified by the {@link DebugOptions#Dump}, {@link DebugOptions#Log}, - * {@link DebugOptions#Count} and {@link DebugOptions#Time} options. + * Implements the filter specified by options such as {@link DebugOptions#Dump}, + * {@link DebugOptions#Log}, {@link DebugOptions#Count} and {@link DebugOptions#Time}. + * + * See here for a description of the filter syntax. + * *

* These options enable the associated debug facility if their filter matches the * {@linkplain Scope#getQualifiedName() name} of the current scope. For the @@ -37,47 +40,7 @@ * {@link DebugOptions#Count} and {@link DebugOptions#Time} options don't have a level, for them * {@code level = 0} means disabled and a {@code level > 0} means enabled. *

- * A filter is a list of comma-separated terms of the form {@code [:]}. {@code - * } is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it - * is interpreted as a substring. If {@code } is empty, it matches every scope. If {@code : - * } is omitted, it defaults to {@link DebugContext#BASIC_LEVEL}. The term {@code ~} - * is a shorthand for {@code :0} to disable a debug facility for a pattern. - *

- * The resulting log level of a scope is determined by the last matching term. If no term - * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log - * level of {@link DebugContext#BASIC_LEVEL}. - * - *

Examples of filters

- * - *
    - *
  • (empty string)
    - * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}. - * - *
  • {@code :1}
    - * Matches any scope with log level 1. - * - *
  • {@code *}
    - * Matches any scope with log level {@link DebugContext#BASIC_LEVEL}. - * - *
  • {@code CodeGen,CodeInstall}
    - * Matches scopes containing "CodeGen" or "CodeInstall", both with log level - * {@link DebugContext#BASIC_LEVEL}. - * - *
  • {@code CodeGen:2,CodeInstall:1}
    - * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. - * - *
  • {@code :1,Dead:2}
    - * Matches scopes containing "Dead" with log level 2, and all other scopes with log level 1. - * - *
  • {@code :1,Dead:0}
    - * Matches all scopes with log level 1, except those containing "Dead". - * - *
  • {@code Code*}
    - * Matches scopes starting with "Code" with log level {@link DebugContext#BASIC_LEVEL}. - * - *
  • {@code Code,~Dead}
    - * Matches scopes containing "Code" but not "Dead", with log level {@link DebugContext#BASIC_LEVEL}. - *
+ * The syntax for a filter is explained here. */ final class DebugFilter { @@ -148,13 +111,16 @@ if (terms == null) { return DebugContext.BASIC_LEVEL; } else { - int level = 0; + int defaultLevel = 0; + int level = -1; for (Term t : terms) { - if (t.matches(input)) { + if (t.isMatchAny()) { + defaultLevel = t.level; + } else if (t.matches(input)) { level = t.level; } } - return level; + return level == -1 ? defaultLevel : level; } } @@ -176,7 +142,7 @@ Term(String filter, int level) { this.level = level; - if (filter.isEmpty()) { + if (filter.isEmpty() || filter.equals("*")) { this.pattern = null; } else if (filter.contains("*") || filter.contains("?")) { this.pattern = Pattern.compile(MethodFilter.createGlobString(filter)); @@ -192,6 +158,10 @@ return pattern == null || pattern.matcher(input).matches(); } + public boolean isMatchAny() { + return pattern == null; + } + @Override public String toString() { return (pattern == null ? ".*" : pattern.toString()) + ":" + level; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Tue Sep 05 10:09:44 2017 -0700 @@ -64,24 +64,28 @@ "An empty value enables all memory usage trackers unconditionally.", type = OptionType.Debug) public static final OptionKey MemUseTrackers = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which counting is enabled (see DebugFilter and Debug.counter). " + + @Option(help = "Pattern for specifying scopes in which counters are enabled. " + + "See the Dump option for the pattern syntax. " + "An empty value enables all counters unconditionally.", type = OptionType.Debug) public static final OptionKey Count = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which memory use tracking is enabled (see DebugFilter and Debug.counter). " + + @Option(help = "Pattern for specifying scopes in which memory use tracking is enabled. " + + "See the Dump option for the pattern syntax. " + "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug) public static final OptionKey TrackMemUse = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which timing is enabled (see DebugFilter and Debug.timer). " + + @Option(help = "Pattern for specifying scopes in which timing is enabled. " + + "See the Dump option for the pattern syntax. " + "An empty value enables all timers unconditionally.", type = OptionType.Debug) public static final OptionKey Time = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which verification is enabled (see DebugFilter and Debug.verify).", type = OptionType.Debug) + @Option(help = "Pattern for specifying scopes in which logging is enabled. " + + "See the Dump option for the pattern syntax.", type = OptionType.Debug) public static final OptionKey Verify = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which dumping is enabled (see DebugFilter and Debug.dump)", type = OptionType.Debug) + @Option(help = "file:doc-files/DumpHelp.txt", type = OptionType.Debug) public static final OptionKey Dump = new OptionKey<>(null); - @Option(help = "Pattern for scope(s) in which logging is enabled (see DebugFilter and Debug.log)", type = OptionType.Debug) + @Option(help = "Pattern for specifying scopes in which logging is enabled. " + + "See the Dump option for the pattern syntax.", type = OptionType.Debug) public static final OptionKey Log = new OptionKey<>(null); - - @Option(help = "Pattern for filtering debug scope output based on method context (see MethodFilter)", type = OptionType.Debug) + @Option(help = "file:doc-files/MethodFilterHelp.txt") public static final OptionKey MethodFilter = new OptionKey<>(null); @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug) public static final OptionKey MethodFilterRootOnly = new OptionKey<>(false); @@ -89,13 +93,11 @@ "The argument is substring matched against the simple name of the phase class", type = OptionType.Debug) public static final OptionKey DumpOnPhaseChange = new OptionKey<>(null); - @Option(help = "Listst the console at VM shutdown the metric names available to the Timers, Counters and MemUseTrackers option. " + + @Option(help = "Lists on the console at VM shutdown the metric names available to the Timers, Counters and MemUseTrackers options. " + "Note that this only lists the metrics that were initialized during the VM execution and so " + "will not include metrics for compiler code that is not executed.", type = OptionType.Debug) public static final OptionKey ListMetrics = new OptionKey<>(false); - @Option(help = "File to which metrics are dumped per compilation. A CSV format is used if the file ends with .csv " + - "otherwise a more human readable format is used. The fields in the CSV format are: " + - "compilable, compilable_identity, compilation_nr, compilation_id, metric_name, metric_value", type = OptionType.Debug) + @Option(help = "file:doc-files/MetricsFileHelp.txt", type = OptionType.Debug) public static final OptionKey MetricsFile = new OptionKey<>(null); @Option(help = "File to which aggregated metrics are dumped at shutdown. A CSV format is used if the file ends with .csv " + "otherwise a more human readable format is used. If not specified, metrics are dumped to the console.", type = OptionType.Debug) @@ -149,7 +151,7 @@ @Option(help = "Enable dumping canonical text from for graphs.", type = OptionType.Debug) public static final OptionKey PrintCanonicalGraphStrings = new OptionKey<>(false); @Option(help = "Choose format used when dumping canonical text for graphs: " + - "0 gives a scheduled graph (better for spotting changes involving the schedule)" + + "0 gives a scheduled graph (better for spotting changes involving the schedule) " + "while 1 gives a CFG containing expressions rooted at fixed nodes (better for spotting small structure differences)", type = OptionType.Debug) public static final OptionKey PrintCanonicalGraphStringFlavor = new OptionKey<>(0); @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MethodFilter.java Tue Sep 05 10:09:44 2017 -0700 @@ -31,66 +31,7 @@ /** * This class implements a method filter that can filter based on class name, method name and - * parameters. The syntax for the source pattern that is passed to the constructor is as follows: - * - *
- * SourcePatterns = SourcePattern ["," SourcePatterns] .
- * SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] .
- * Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" .
- * Class = { package "." } class .
- * 
- * - * - * Glob pattern matching (*, ?) is allowed in all parts of the source pattern. Examples for valid - * filters are: - * - *
    - *
  • - * - *
    - * visit(Argument;BlockScope)
    - * 
    - * - * Matches all methods named "visit", with the first parameter of type "Argument", and the second - * parameter of type "BlockScope". The packages of the parameter types are irrelevant.
  • - *
  • - * - *
    - * arraycopy(Object;;;;)
    - * 
    - * - * Matches all methods named "arraycopy", with the first parameter of type "Object", and four more - * parameters of any type. The packages of the parameter types are irrelevant.
  • - *
  • - * - *
    - * org.graalvm.compiler.core.graph.PostOrderNodeIterator.*
    - * 
    - * - * Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator".
  • - *
  • - * - *
    - * *
    - * 
    - * - * Matches all methods in all classes
  • - *
  • - * - *
    - * org.graalvm.compiler.core.graph.*.visit
    - * 
    - * - * Matches all methods named "visit" in classes in the package "org.graalvm.compiler.core.graph". - *
  • - * - *
    - * arraycopy,toString
    - * 
    - * - * Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an or - * operator.
  • - *
+ * parameters. The syntax for a filter is explained here. */ public class MethodFilter { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/DumpHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/DumpHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,61 @@ +Filter pattern for specifying scopes in which dumping is enabled. + +A filter is a list of comma-separated terms of the form: + + [:] + +If contains a "*" or "?" character, it is interpreted as a glob pattern. +Otherwise, it is interpreted as a substring. If is empty, it +matches every scope. If : is omitted, it defaults to 1. The term +~ is a shorthand for :0 to disable a debug facility for a pattern. + +The default log level is 0 (disabled). Terms with an empty pattern set +the default log level to the specified value. The last +matching term with a non-empty pattern selects the level specified. If +no term matches, the log level is the default level. A filter with no +terms matches every scope with a log level of 1. + +Examples of debug filters: +--------- + (empty string) + + Matches any scope with level 1. +--------- + :1 + + Matches any scope with level 1. +--------- + * + + Matches any scope with level 1. +--------- + CodeGen,CodeInstall + + Matches scopes containing "CodeGen" or "CodeInstall", both with level 1. +--------- + CodeGen:2,CodeInstall:1 + + Matches scopes containing "CodeGen" with level 2, or "CodeInstall" with level 1. +--------- + Outer:2,Inner:0} + + Matches scopes containing "Outer" with log level 2, or "Inner" with log level 0. If the scope + name contains both patterns then the log level will be 0. This is useful for silencing subscopes. +--------- + :1,Dead:2 + + Matches scopes containing "Dead" with level 2, and all other scopes with level 1. +--------- + Dead:0,:1 + + Matches all scopes with level 1, except those containing "Dead". Note that the location of + the :1 doesn't matter since it's specifying the default log level so it's the same as + specifying :1,Dead:0. +--------- + Code* + + Matches scopes starting with "Code" with level 1. +--------- + Code,~Dead + + Matches scopes containing "Code" but not "Dead", with level 1. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MethodFilterHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MethodFilterHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,40 @@ +Pattern for filtering debug scope output based on method context. +The syntax for a pattern is: + + SourcePatterns = SourcePattern ["," SourcePatterns] . + SourcePattern = [ Class "." ] method [ "(" [ Parameter { ";" Parameter } ] ")" ] . + Parameter = Class | "int" | "long" | "float" | "double" | "short" | "char" | "boolean" . + Class = { package "." } class . + +Glob pattern matching (*, ?) is allowed in all parts of the source pattern. + +Examples of method filters: +--------- + visit(Argument;BlockScope) + + Matches all methods named "visit", with the first parameter of + type "Argument", and the second parameter of type "BlockScope". + The packages of the parameter types are irrelevant. +--------- + arraycopy(Object;;;;) + + Matches all methods named "arraycopy", with the first parameter + of type "Object", and four more parameters of any type. The + packages of the parameter types are irrelevant. +--------- + org.graalvm.compiler.core.graph.PostOrderNodeIterator.* + + Matches all methods in the class "org.graalvm.compiler.core.graph.PostOrderNodeIterator". +--------- + * + + Matches all methods in all classes +--------- + org.graalvm.compiler.core.graph.*.visit + + Matches all methods named "visit" in classes in the package + "org.graalvm.compiler.core.graph". +--------- + arraycopy,toString + + Matches all methods named "arraycopy" or "toString", meaning that ',' acts as an or operator. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MetricsFileHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/doc-files/MetricsFileHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,11 @@ +File to which metrics are dumped per compilation. +A CSV format is used if the file ends with .csv otherwise a more +human readable format is used. The fields in the CSV format are: + compilable - method being compiled + compilable_identity - identity hash code of compilable + compilation_nr - where this compilation lies in the ordered + sequence of all compilations identified by + compilable_identity + compilation_id - runtime issued identifier for the compilation + metric_name - name of metric + metric_value - value of metric diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Tue Sep 05 10:09:44 2017 -0700 @@ -931,7 +931,7 @@ } /** - * @returns true if the node has no inputs and no successors + * @return true if the node has no inputs and no successors */ public boolean isLeafNode() { return isLeafNode; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -40,20 +40,12 @@ import org.graalvm.compiler.test.SubprocessUtil; import org.graalvm.compiler.test.SubprocessUtil.Subprocess; import org.junit.Assert; -import org.junit.Assume; import org.junit.Test; /** * Tests support for dumping graphs and other info useful for debugging a compiler crash. */ public class CompilationWrapperTest extends GraalCompilerTest { - public CompilationWrapperTest() { - try { - Class.forName("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException ex) { - Assume.assumeNoException("skip this test if there is no java.management JDK9 module around", ex); - } - } /** * Tests compilation requested by the VM. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,6 +25,7 @@ import java.util.ArrayList; import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.junit.Test; /** @@ -84,4 +85,20 @@ } test("cloneList", list); } + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + return super.editGraphBuilderConfiguration(conf.withNodeSourcePosition(true)); + } + + static final int[] ARRAY = new int[]{1, 2, 4, 3}; + + public static int[] cloneConstantArray() { + return ARRAY.clone(); + } + + @Test + public void testCloneConstantArray() { + test("cloneConstantArray"); + } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Tue Sep 05 10:09:44 2017 -0700 @@ -157,8 +157,8 @@ /** * Selects and instantiates a {@link CompilerConfigurationFactory}. The selection algorithm is * as follows: if {@code name} is non-null, then select the factory with the same name else if - * {@link Options#CompilerConfiguration}{@code .getValue()} is non-null then select the factory - * whose name matches the value else select the factory with the highest + * {@code Options.CompilerConfiguration.getValue()} is non-null then select the factory whose + * name matches the value else select the factory with the highest * {@link #autoSelectionPriority} value. * * @param name the name of the compiler configuration to select (optional) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java Tue Sep 05 10:09:44 2017 -0700 @@ -23,7 +23,6 @@ package org.graalvm.compiler.hotspot; import java.util.Formatter; -import java.util.Objects; /** * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API @@ -40,10 +39,6 @@ private static final int JVMCI8_MIN_MAJOR_VERSION = 0; private static final int JVMCI8_MIN_MINOR_VERSION = 29; - // MAX_VALUE indicates that no current EA version is compatible with Graal. - // Note: Keep README.md in sync with the EA version support checked here. - private static final int JVMCI9_MIN_EA_BUILD = 176; - private static void failVersionCheck(boolean exit, String reason, Object... args) { Formatter errorMessage = new Formatter().format(reason, args); String javaHome = System.getProperty("java.home"); @@ -55,7 +50,7 @@ if (System.getProperty("java.specification.version").compareTo("1.9") < 0) { errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html"); } else { - errorMessage.format("Download the latest JDK 9 EA from https://jdk9.java.net/download/"); + errorMessage.format("Download the latest JDK 9 build from https://jdk9.java.net/download/"); } String value = System.getenv("JVMCI_VERSION_CHECK"); if ("warn".equals(value)) { @@ -119,34 +114,11 @@ // Allow local builds return; } - // http://openjdk.java.net/jeps/223 - if (vmVersion.startsWith("9+")) { - int start = "9+".length(); - int end = start; - end = start; - while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) { - end++; - } - int build; - try { - build = Integer.parseInt(vmVersion.substring(start, end)); - } catch (NumberFormatException e) { - failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" + - "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion); - return; - } - if (build >= JVMCI9_MIN_EA_BUILD) { - return; - } - if (Objects.equals(JVMCI9_MIN_EA_BUILD, Integer.MAX_VALUE)) { - failVersionCheck(exitOnFailure, "This version of Graal is not compatible with any JDK 9 Early Access build.%n"); - } else { - failVersionCheck(exitOnFailure, "The VM is an insufficiently recent EA JDK9 build for Graal: %d < %d.%n", build, JVMCI9_MIN_EA_BUILD); - } + if (vmVersion.startsWith("9-ea")) { + failVersionCheck(exitOnFailure, "This version of Graal is not compatible with JDK 9 Early Access builds.%n"); return; } else { - // Graal will be compatible with all JDK versions as of 9 GA - // until a JVMCI API change is made in a 9u or later release. + // Graal is compatible with all JDK versions as of 9 GA. } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java Tue Sep 05 10:09:44 2017 -0700 @@ -41,7 +41,6 @@ import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions; import org.graalvm.compiler.nodes.debug.DynamicCounterNode; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -69,20 +68,8 @@ * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise * they will be displayed as a total number. * - *

Example

In order to create statistics about allocations within the DaCapo pmd benchmark - * the following steps are necessary: - *
    - *
  • Set {@code -XX:JVMCICounterSize=value}. The actual required value depends on the granularity - * of the profiling, 10000 should be enough for most cases.
  • - *
  • Also: {@code -XX:+/-JVMCICountersExcludeCompiler} specifies whether the numbers generated by - * compiler threads should be excluded (default: true).
  • - *
  • Start the DaCapo pmd benchmark with - * {@code "-Dgraal.BenchmarkDynamicCounters=err, starting ====, PASSED in "} and - * {@code -Dgraal.ProfileAllocations=true}.
  • - *
  • The numbers will only include allocation from compiled code!
  • - *
  • The counters can be further configured by modifying the - * {@link HotspotSnippetsOptions#ProfileAllocationsContext} flag..
  • - *
+ * See here for a detailed example of how to use + * benchmark counters. */ public class BenchmarkCounters { @@ -94,11 +81,7 @@ @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds", type = OptionType.Debug) public static final OptionKey TimedDynamicCounters = new OptionKey<>(-1); - @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" + - "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" + - "Examples:%n" + - " dacapo = 'err, starting =====, PASSED in'%n" + - " specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug) + @Option(help = "file:doc-files/BenchmarkDynamicCountersHelp.txt", type = OptionType.Debug) public static final OptionKey BenchmarkDynamicCounters = new OptionKey<>(null); @Option(help = "Use grouping separators for number printing", type = OptionType.Debug) public static final OptionKey DynamicCountersPrintGroupSeparator = new OptionKey<>(true); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,24 @@ +Turn on the benchmark counters, and listen for specific patterns on System.out/System.err. +The format of this option is: + + (err|out),start pattern,end pattern + +You can use "~" to match 1 or more digits. +Examples: + + err, starting =====, PASSED in + out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends: + +The first pattern matches DaCapo output and the second matches SPECjvm2008 output. + +As a more detailed example, here are the options to use for getting statistics +about allocations within the DaCapo pmd benchmark: + + -XX:JVMCICounterSize= -XX:-JVMCICountersExcludeCompiler \ + -Dgraal.BenchmarkDynamicCounters="err, starting ====, PASSED in " \ + -Dgraal.ProfileAllocations=true + +The JVMCICounterSize value depends on the granularity of the profiling - +10000 should be sufficient. Omit JVMCICountersExcludeCompiler to exclude +counting allocations on the compiler threads. +The counters can be further configured by the ProfileAllocationsContext option. \ No newline at end of file diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases; +import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; import java.util.ListIterator; @@ -98,10 +99,12 @@ midTierLowering.add(new ReplaceConstantNodesPhase()); // Replace inlining policy - ListIterator> iter = ret.getHighTier().findPhase(InliningPhase.class); - InliningPhase inlining = (InliningPhase) iter.previous(); - CanonicalizerPhase canonicalizer = inlining.getCanonicalizer(); - iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer)); + if (Inline.getValue(options)) { + ListIterator> iter = ret.getHighTier().findPhase(InliningPhase.class); + InliningPhase inlining = (InliningPhase) iter.previous(); + CanonicalizerPhase canonicalizer = inlining.getCanonicalizer(); + iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer)); + } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotspotSnippetsOptions.java Tue Sep 05 10:09:44 2017 -0700 @@ -51,7 +51,7 @@ @Option(help = "Enable profiling of allocation sites.", type = OptionType.Debug) public static final OptionKey ProfileAllocations = new OptionKey<>(false); - @Option(help = "Control the naming of the counters when using ProfileAllocations.", type = OptionType.Debug) + @Option(help = "file:doc-files/ProfileAllocationsContextHelp.txt", type = OptionType.Debug) public static final EnumOptionKey ProfileAllocationsContext = new EnumOptionKey<>(ProfileContext.AllocatingMethod); @Option(help = "Enable profiling of monitor operations.", type = OptionType.Debug) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/doc-files/ProfileAllocationsContextHelp.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/doc-files/ProfileAllocationsContextHelp.txt Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,8 @@ +Control the naming and granularity of the counters when using ProfileAllocations. +The accepted values are: + AllocatingMethod - a counter per method + InstanceOrArray - one counter for all instance allocations and + one counter for all array allocations + AllocatedType - one counter per allocated type + AllocatedTypesInMethod - one counter per allocated type, per method + \ No newline at end of file diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java Tue Sep 05 10:09:44 2017 -0700 @@ -36,6 +36,8 @@ import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.util.EconomicMap; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; + public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure { private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure(); @@ -75,32 +77,18 @@ for (double d : exitStates.getValues()) { exitProbability += d; } - exitProbability = Math.min(1D, exitProbability); - if (exitProbability < ControlFlowGraph.MIN_PROBABILITY) { - exitProbability = ControlFlowGraph.MIN_PROBABILITY; - } - assert exitProbability <= 1D && exitProbability >= 0D; - double loopFrequency = 1D / exitProbability; + exitProbability = Math.min(1.0, exitProbability); + exitProbability = Math.max(ControlFlowGraph.MIN_PROBABILITY, exitProbability); + double loopFrequency = 1.0 / exitProbability; loop.setLoopFrequency(loopFrequency); double adjustmentFactor = initialState * loopFrequency; - exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor)); + exitStates.replaceAll((exitNode, probability) -> multiplyProbabilities(probability, adjustmentFactor)); return exitStates; } /** - * Multiplies a and b and saturates the result to {@link ControlFlowGraph#MAX_PROBABILITY}. - */ - public static double multiplySaturate(double a, double b) { - double r = a * b; - if (r > ControlFlowGraph.MAX_PROBABILITY) { - return ControlFlowGraph.MAX_PROBABILITY; - } - return r; - } - - /** * Computes the frequencies of all loops in the given graph. This is done by performing a * reverse postorder iteration and computing the probability of all fixed nodes. The combined * probability of all exits of a loop can be used to compute the loop's expected frequency. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java Tue Sep 05 10:09:44 2017 -0700 @@ -68,6 +68,8 @@ public AArch64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { super(TYPE); + + assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Tue Sep 05 10:09:44 2017 -0700 @@ -33,6 +33,8 @@ import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.LIRInstructionClass; @@ -69,6 +71,10 @@ @Temp({REG}) protected Value temp2; @Temp({REG}) protected Value temp3; @Temp({REG}) protected Value temp4; + + @Temp({REG, ILLEGAL}) protected Value temp5; + @Temp({REG, ILLEGAL}) protected Value tempXMM; + @Temp({REG, ILLEGAL}) protected Value vectorTemp1; @Temp({REG, ILLEGAL}) protected Value vectorTemp2; @@ -91,6 +97,15 @@ this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); + this.temp5 = kind.isNumericFloat() ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL; + if (kind == JavaKind.Float) { + this.tempXMM = tool.newVariable(LIRKind.value(AMD64Kind.SINGLE)); + } else if (kind == JavaKind.Double) { + this.tempXMM = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + } else { + this.tempXMM = Value.ILLEGAL; + } + // We only need the vector temporaries if we generate SSE code. if (supportsSSE41(tool.target())) { this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); @@ -170,10 +185,14 @@ Label loop = new Label(); Label compareTail = new Label(); + boolean requiresNaNCheck = kind.isNumericFloat(); + Label loopCheck = new Label(); + Label nanCheck = new Label(); + // Compare 16-byte vectors masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes) masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareTail); + masm.jcc(ConditionFlag.Zero, compareTail); masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); @@ -186,13 +205,24 @@ masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); masm.pxor(vector1, vector2); masm.ptest(vector1, vector1); - masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jcc(ConditionFlag.NotZero, requiresNaNCheck ? nanCheck : falseLabel); + + masm.bind(loopCheck); masm.addq(length, SSE4_1_VECTOR_SIZE); masm.jcc(ConditionFlag.NotZero, loop); masm.testl(result, result); masm.jcc(ConditionFlag.Zero, trueLabel); + if (requiresNaNCheck) { + Label unalignedCheck = new Label(); + masm.jmpb(unalignedCheck); + masm.bind(nanCheck); + emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, SSE4_1_VECTOR_SIZE); + masm.jmpb(loopCheck); + masm.bind(unalignedCheck); + } + /* * Compare the remaining bytes with an unaligned memory load aligned to the end of the * array. @@ -201,7 +231,12 @@ masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); masm.pxor(vector1, vector2); masm.ptest(vector1, vector1); - masm.jcc(ConditionFlag.NotZero, falseLabel); + if (requiresNaNCheck) { + masm.jcc(ConditionFlag.Zero, trueLabel); + emitFloatCompareWithinRange(crb, masm, array1, array2, result, -SSE4_1_VECTOR_SIZE, falseLabel, SSE4_1_VECTOR_SIZE); + } else { + masm.jcc(ConditionFlag.NotZero, falseLabel); + } masm.jmp(trueLabel); masm.bind(compareTail); @@ -233,10 +268,14 @@ Label loop = new Label(); Label compareTail = new Label(); + boolean requiresNaNCheck = kind.isNumericFloat(); + Label loopCheck = new Label(); + Label nanCheck = new Label(); + // Compare 16-byte vectors masm.andl(result, AVX_VECTOR_SIZE - 1); // tail count (in bytes) masm.andl(length, ~(AVX_VECTOR_SIZE - 1)); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareTail); + masm.jcc(ConditionFlag.Zero, compareTail); masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); @@ -249,13 +288,24 @@ masm.vmovdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); masm.vpxor(vector1, vector1, vector2); masm.vptest(vector1, vector1); - masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jcc(ConditionFlag.NotZero, requiresNaNCheck ? nanCheck : falseLabel); + + masm.bind(loopCheck); masm.addq(length, AVX_VECTOR_SIZE); masm.jcc(ConditionFlag.NotZero, loop); masm.testl(result, result); masm.jcc(ConditionFlag.Zero, trueLabel); + if (requiresNaNCheck) { + Label unalignedCheck = new Label(); + masm.jmpb(unalignedCheck); + masm.bind(nanCheck); + emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, AVX_VECTOR_SIZE); + masm.jmpb(loopCheck); + masm.bind(unalignedCheck); + } + /* * Compare the remaining bytes with an unaligned memory load aligned to the end of the * array. @@ -264,7 +314,12 @@ masm.vmovdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -AVX_VECTOR_SIZE)); masm.vpxor(vector1, vector1, vector2); masm.vptest(vector1, vector1); - masm.jcc(ConditionFlag.NotZero, falseLabel); + if (requiresNaNCheck) { + masm.jcc(ConditionFlag.Zero, trueLabel); + emitFloatCompareWithinRange(crb, masm, array1, array2, result, -AVX_VECTOR_SIZE, falseLabel, AVX_VECTOR_SIZE); + } else { + masm.jcc(ConditionFlag.NotZero, falseLabel); + } masm.jmp(trueLabel); masm.bind(compareTail); @@ -283,11 +338,15 @@ Label loop = new Label(); Label compareTail = new Label(); + boolean requiresNaNCheck = kind.isNumericFloat(); + Label loopCheck = new Label(); + Label nanCheck = new Label(); + Register temp = asRegister(temp4); masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes) masm.andl(length, ~(VECTOR_SIZE - 1)); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareTail); + masm.jcc(ConditionFlag.Zero, compareTail); masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); @@ -298,12 +357,27 @@ masm.bind(loop); masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0)); masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.jcc(ConditionFlag.NotEqual, requiresNaNCheck ? nanCheck : falseLabel); + + masm.bind(loopCheck); masm.addq(length, VECTOR_SIZE); masm.jccb(ConditionFlag.NotZero, loop); masm.testl(result, result); - masm.jccb(ConditionFlag.Zero, trueLabel); + masm.jcc(ConditionFlag.Zero, trueLabel); + + if (requiresNaNCheck) { + // NaN check is slow path and hence placed outside of the main loop. + Label unalignedCheck = new Label(); + masm.jmpb(unalignedCheck); + masm.bind(nanCheck); + // At most two iterations, unroll in the emitted code. + for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) { + emitFloatCompare(masm, array1, array2, length, offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); + } + masm.jmpb(loopCheck); + masm.bind(unalignedCheck); + } /* * Compare the remaining bytes with an unaligned memory load aligned to the end of the @@ -311,7 +385,15 @@ */ masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE)); masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE)); - masm.jccb(ConditionFlag.NotEqual, falseLabel); + if (requiresNaNCheck) { + masm.jcc(ConditionFlag.Equal, trueLabel); + // At most two iterations, unroll in the emitted code. + for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) { + emitFloatCompare(masm, array1, array2, result, -VECTOR_SIZE + offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); + } + } else { + masm.jccb(ConditionFlag.NotEqual, falseLabel); + } masm.jmpb(trueLabel); masm.bind(compareTail); @@ -333,8 +415,13 @@ masm.jccb(ConditionFlag.Zero, compare2Bytes); masm.movl(temp, new AMD64Address(array1, 0)); masm.cmpl(temp, new AMD64Address(array2, 0)); - masm.jccb(ConditionFlag.NotEqual, falseLabel); - + if (kind == JavaKind.Float) { + masm.jccb(ConditionFlag.Equal, trueLabel); + emitFloatCompare(masm, array1, array2, Register.None, 0, falseLabel, true); + masm.jmpb(trueLabel); + } else { + masm.jccb(ConditionFlag.NotEqual, falseLabel); + } if (kind.getByteCount() <= 2) { // Move array pointers forward. masm.leaq(array1, new AMD64Address(array1, 4)); @@ -372,6 +459,71 @@ } } + /** + * Emits code to fall through if {@code src} is NaN, otherwise jump to {@code branchOrdered}. + */ + private void emitNaNCheck(AMD64MacroAssembler masm, AMD64Address src, Label branchIfNonNaN) { + assert kind.isNumericFloat(); + Register tempXMMReg = asRegister(tempXMM); + if (kind == JavaKind.Float) { + masm.movflt(tempXMMReg, src); + } else { + masm.movdbl(tempXMMReg, src); + } + SSEOp.UCOMIS.emit(masm, kind == JavaKind.Float ? OperandSize.PS : OperandSize.PD, tempXMMReg, tempXMMReg); + masm.jcc(ConditionFlag.NoParity, branchIfNonNaN); + } + + /** + * Emits code to compare if two floats are bitwise equal or both NaN. + */ + private void emitFloatCompare(AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, boolean skipBitwiseCompare) { + AMD64Address address1 = new AMD64Address(base1, index, Scale.Times1, offset); + AMD64Address address2 = new AMD64Address(base2, index, Scale.Times1, offset); + + Label bitwiseEqual = new Label(); + + if (!skipBitwiseCompare) { + // Bitwise compare + Register temp = asRegister(temp4); + + if (kind == JavaKind.Float) { + masm.movl(temp, address1); + masm.cmpl(temp, address2); + } else { + masm.movq(temp, address1); + masm.cmpq(temp, address2); + } + masm.jccb(ConditionFlag.Equal, bitwiseEqual); + } + + emitNaNCheck(masm, address1, falseLabel); + emitNaNCheck(masm, address2, falseLabel); + + masm.bind(bitwiseEqual); + } + + /** + * Emits code to compare float equality within a range. + */ + private void emitFloatCompareWithinRange(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, int range) { + assert kind.isNumericFloat(); + Label loop = new Label(); + Register i = asRegister(temp5); + + masm.movq(i, range); + masm.negq(i); + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + emitFloatCompare(masm, base1, base2, index, offset, falseLabel, kind.getByteCount() == range); + masm.addq(index, kind.getByteCount()); + masm.addq(i, kind.getByteCount()); + masm.jccb(ConditionFlag.NotZero, loop); + // Floats within the range are equal, revert change to the register index + masm.subq(index, range); + } + private static final Unsafe UNSAFE = initUnsafe(); private static Unsafe initUnsafe() { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java Tue Sep 05 10:09:44 2017 -0700 @@ -78,6 +78,8 @@ public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, AllocatableValue result, AllocatableValue array1, AllocatableValue array2, AllocatableValue length) { super(TYPE, SIZE); + + assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java Tue Sep 05 10:09:44 2017 -0700 @@ -59,7 +59,7 @@ if (isNumericInteger(a.getPlatformKind())) { LIRKind aKind = a.getValueKind(LIRKind.class); LIRKind bKind = b.getValueKind(LIRKind.class); - assert a.getPlatformKind() == b.getPlatformKind(); + assert a.getPlatformKind() == b.getPlatformKind() : a.getPlatformKind() + " vs. " + b.getPlatformKind(); if (aKind.isUnknownReference()) { resultKind = aKind; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java Tue Sep 05 10:09:44 2017 -0700 @@ -51,6 +51,8 @@ try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { LoopsData dataCounted = new LoopsData(graph); dataCounted.detectedCountedLoops(); + Graph.Mark mark = graph.getMark(); + boolean prePostInserted = false; for (LoopEx loop : dataCounted.countedLoops()) { if (!LoopTransformations.isUnrollableLoop(loop)) { continue; @@ -59,9 +61,10 @@ if (loop.loopBegin().isSimpleLoop()) { // First perform the pre/post transformation and do the partial // unroll when we come around again. - LoopTransformations.insertPrePostLoops(loop, graph); + LoopTransformations.insertPrePostLoops(loop); + prePostInserted = true; } else { - LoopTransformations.partialUnroll(loop, graph); + LoopTransformations.partialUnroll(loop); } changed = true; } @@ -72,11 +75,25 @@ canonicalizer.applyIncremental(graph, context, listener.getNodes()); listener.getNodes().clear(); } + + assert !prePostInserted || checkCounted(graph, mark); } } } } + private static boolean checkCounted(StructuredGraph graph, Graph.Mark mark) { + LoopsData dataCounted; + dataCounted = new LoopsData(graph); + dataCounted.detectedCountedLoops(); + for (LoopEx anyLoop : dataCounted.loops()) { + if (graph.isNew(mark, anyLoop.loopBegin())) { + assert anyLoop.isCounted() : "pre/post transformation loses counted loop " + anyLoop.loopBegin(); + } + } + return true; + } + @Override public boolean checkContract() { return false; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Tue Sep 05 10:09:44 2017 -0700 @@ -31,6 +31,7 @@ import java.util.List; import org.graalvm.compiler.core.common.RetryableBailoutException; +import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.Mark; @@ -145,9 +146,9 @@ // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) } - public static void partialUnroll(LoopEx loop, StructuredGraph graph) { + public static void partialUnroll(LoopEx loop) { assert loop.loopBegin().isMainLoop(); - graph.getDebug().log("LoopPartialUnroll %s", loop); + loop.loopBegin().graph().getDebug().log("LoopPartialUnroll %s", loop); LoopFragmentInside newSegment = loop.inside().duplicate(); newSegment.insertWithinAfter(loop); @@ -222,72 +223,73 @@ // The pre loop is constrained to one iteration for now and will likely // be updated to produce vector alignment if applicable. - public static void insertPrePostLoops(LoopEx loop, StructuredGraph graph) { + public static LoopBeginNode insertPrePostLoops(LoopEx loop) { + StructuredGraph graph = loop.loopBegin().graph(); graph.getDebug().log("LoopTransformations.insertPrePostLoops %s", loop); LoopFragmentWhole preLoop = loop.whole(); CountedLoopInfo preCounted = loop.counted(); IfNode preLimit = preCounted.getLimitTest(); - if (preLimit != null) { - LoopBeginNode preLoopBegin = loop.loopBegin(); - InductionVariable preIv = preCounted.getCounter(); - LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit(); - FixedNode continuationNode = preLoopExitNode.next(); + assert preLimit != null; + LoopBeginNode preLoopBegin = loop.loopBegin(); + InductionVariable preIv = preCounted.getCounter(); + LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit(); + FixedNode continuationNode = preLoopExitNode.next(); - // Each duplication is inserted after the original, ergo create the post loop first - LoopFragmentWhole mainLoop = preLoop.duplicate(); - LoopFragmentWhole postLoop = preLoop.duplicate(); - preLoopBegin.incrementSplits(); - preLoopBegin.incrementSplits(); - preLoopBegin.setPreLoop(); - graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After duplication"); - LoopBeginNode mainLoopBegin = mainLoop.getDuplicatedNode(preLoopBegin); - mainLoopBegin.setMainLoop(); - LoopBeginNode postLoopBegin = postLoop.getDuplicatedNode(preLoopBegin); - postLoopBegin.setPostLoop(); + // Each duplication is inserted after the original, ergo create the post loop first + LoopFragmentWhole mainLoop = preLoop.duplicate(); + LoopFragmentWhole postLoop = preLoop.duplicate(); + preLoopBegin.incrementSplits(); + preLoopBegin.incrementSplits(); + preLoopBegin.setPreLoop(); + graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After duplication"); + LoopBeginNode mainLoopBegin = mainLoop.getDuplicatedNode(preLoopBegin); + mainLoopBegin.setMainLoop(); + LoopBeginNode postLoopBegin = postLoop.getDuplicatedNode(preLoopBegin); + postLoopBegin.setPostLoop(); - EndNode postEndNode = getBlockEndAfterLoopExit(postLoopBegin); - AbstractMergeNode postMergeNode = postEndNode.merge(); - LoopExitNode postLoopExitNode = postLoopBegin.getSingleLoopExit(); + EndNode postEndNode = getBlockEndAfterLoopExit(postLoopBegin); + AbstractMergeNode postMergeNode = postEndNode.merge(); + LoopExitNode postLoopExitNode = postLoopBegin.getSingleLoopExit(); - // Update the main loop phi initialization to carry from the pre loop - for (PhiNode prePhiNode : preLoopBegin.phis()) { - PhiNode mainPhiNode = mainLoop.getDuplicatedNode(prePhiNode); - mainPhiNode.setValueAt(0, prePhiNode); - } + // Update the main loop phi initialization to carry from the pre loop + for (PhiNode prePhiNode : preLoopBegin.phis()) { + PhiNode mainPhiNode = mainLoop.getDuplicatedNode(prePhiNode); + mainPhiNode.setValueAt(0, prePhiNode); + } - EndNode mainEndNode = getBlockEndAfterLoopExit(mainLoopBegin); - AbstractMergeNode mainMergeNode = mainEndNode.merge(); - AbstractEndNode postEntryNode = postLoopBegin.forwardEnd(); + EndNode mainEndNode = getBlockEndAfterLoopExit(mainLoopBegin); + AbstractMergeNode mainMergeNode = mainEndNode.merge(); + AbstractEndNode postEntryNode = postLoopBegin.forwardEnd(); - // In the case of no Bounds tests, we just flow right into the main loop - AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode); - LoopExitNode mainLoopExitNode = mainLoopBegin.getSingleLoopExit(); - mainLoopExitNode.setNext(mainLandingNode); - preLoopExitNode.setNext(mainLoopBegin.forwardEnd()); + // In the case of no Bounds tests, we just flow right into the main loop + AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode); + LoopExitNode mainLoopExitNode = mainLoopBegin.getSingleLoopExit(); + mainLoopExitNode.setNext(mainLandingNode); + preLoopExitNode.setNext(mainLoopBegin.forwardEnd()); - // Add and update any phi edges as per merge usage as needed and update usages - processPreLoopPhis(loop, mainLoop, postLoop); - continuationNode.predecessor().clearSuccessors(); - postLoopExitNode.setNext(continuationNode); - cleanupMerge(postMergeNode, postLoopExitNode); - cleanupMerge(mainMergeNode, mainLandingNode); + // Add and update any phi edges as per merge usage as needed and update usages + processPreLoopPhis(loop, mainLoop, postLoop); + continuationNode.predecessor().clearSuccessors(); + postLoopExitNode.setNext(continuationNode); + cleanupMerge(postMergeNode, postLoopExitNode); + cleanupMerge(mainMergeNode, mainLandingNode); - // Change the preLoop to execute one iteration for now - updateMainLoopLimit(preLimit, preIv, mainLoop); - updatePreLoopLimit(preLimit, preIv, preCounted); - preLoopBegin.setLoopFrequency(1); - mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2)); - postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1)); + // Change the preLoop to execute one iteration for now + updateMainLoopLimit(preLimit, preIv, mainLoop); + updatePreLoopLimit(preLimit, preIv, preCounted); + preLoopBegin.setLoopFrequency(1); + mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2)); + postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1)); - // The pre and post loops don't require safepoints at all - for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) { - graph.removeFixed(safepoint); - } - for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) { - graph.removeFixed(safepoint); - } + // The pre and post loops don't require safepoints at all + for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) { + graph.removeFixed(safepoint); + } + for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) { + graph.removeFixed(safepoint); } graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "InsertPrePostLoops %s", loop); + return mainLoopBegin; } /** @@ -373,7 +375,7 @@ throw GraalError.shouldNotReachHere(); } - // Preloop always performs at least once iteration, so remove that from the main loop. + // Preloop always performs at least one iteration, so remove that from the main loop. ValueNode newLimit = sub(graph, ub, mainStride); // Re-wire the condition with the new limit @@ -445,6 +447,14 @@ return false; } LoopBeginNode loopBegin = loop.loopBegin(); + LogicNode condition = loop.counted().getLimitTest().condition(); + if (!(condition instanceof CompareNode)) { + return false; + } + if (((CompareNode) condition).condition() == Condition.EQ || ((CompareNode) condition).condition() == Condition.NE) { + condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s condition unsupported %s ", loopBegin, ((CompareNode) condition).condition()); + return false; + } if (loopBegin.isMainLoop() || loopBegin.isSimpleLoop()) { // Flow-less loops to partial unroll for now. 3 blocks corresponds to an if that either // exits or continues the loop. There might be fixed and floating work within the loop @@ -452,6 +462,7 @@ if (loop.loop().getBlocks().size() < 3) { return true; } + condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s too large to unroll %s ", loopBegin, loop.loop().getBlocks().size()); } return false; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -22,12 +22,41 @@ */ package org.graalvm.compiler.loop.test; +import java.util.ListIterator; + +import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.LoopEx; +import org.graalvm.compiler.loop.LoopFragmentInside; +import org.graalvm.compiler.loop.LoopsData; +import org.graalvm.compiler.loop.phases.LoopPartialUnrollPhase; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConditionalEliminationPhase; +import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import org.graalvm.compiler.phases.common.DeoptimizationGroupingPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; +import org.graalvm.compiler.phases.common.GuardLoweringPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.junit.Ignore; import org.junit.Test; +import jdk.vm.ci.meta.ResolvedJavaMethod; + public class LoopPartialUnrollTest extends GraalCompilerTest { @Override @@ -41,100 +70,72 @@ return false; } - public static long testMultiplySnippet(int arg) { - long r = 1; - for (int i = 0; branchProbability(0.99, i < arg); i++) { - r += r * i; + public static long sumWithEqualityLimit(int[] text) { + long sum = 0; + for (int i = 0; branchProbability(0.99, i != text.length); ++i) { + sum += volatileInt; } - return r; - } - - @Test - public void testMultiply() { - test("testMultiplySnippet", 9); - } - - public static int testNestedSumSnippet(int d) { - int c = 0; - for (int i = 0; i < d; i++) { - for (int j = 0; branchProbability(0.99, j < i); j++) { - c += c + j & 0x3; - } - } - return c; - } - - @Test - public void testNestedSumBy2() { - for (int i = 0; i < 1000; i++) { - test("testNestedSumBy2Snippet", i); - } + return sum; } - public static int testNestedSumBy2Snippet(int d) { - int c = 0; - for (int i = 0; i < d; i++) { - for (int j = 0; branchProbability(0.99, j < i); j += 2) { - c += c + j & 0x3; - } - } - return c; - } - + @Ignore("equality limits aren't working properly") @Test - public void testNestedSum() { - for (int i = 0; i < 1000; i++) { - test("testNestedSumSnippet", i); - } - } - - public static int testSumDownSnippet(int d) { - int c = 0; - for (int j = d; branchProbability(0.99, j > -4); j--) { - c += c + j & 0x3; - } - return c; - } - - @Test - public void testSumDown() { - test("testSumDownSnippet", 1); - for (int i = 0; i < 160; i++) { - test("testSumDownSnippet", i); - } - } - - public static int testSumDownBy2Snippet(int d) { - int c = 0; - for (int j = d; branchProbability(0.99, j > -4); j -= 2) { - c += c + j & 0x3; - } - return c; - } - - @Test - public void testSumDownBy2() { - test("testSumDownBy2Snippet", 1); - for (int i = 0; i < 160; i++) { - test("testSumDownBy2Snippet", i); + public void testSumWithEqualityLimit() { + for (int i = 0; i < 128; i++) { + int[] data = new int[i]; + test("sumWithEqualityLimit", data); } } @Test public void testLoopCarried() { - test("testLoopCarriedSnippet", 1, 2); - test("testLoopCarriedSnippet", 0, 4); - test("testLoopCarriedSnippet", 4, 0); + for (int i = 0; i < 64; i++) { + test("testLoopCarriedSnippet", i); + } + } + + @Test + public void testLoopCarriedDuplication() { + testDuplicateBody("testLoopCarriedReference", "testLoopCarriedSnippet"); } - public static int testLoopCarriedSnippet(int a, int b) { - int c = a; - int d = b; - for (int j = 0; branchProbability(0.99, j < a); j++) { - d = c; - c += 1; + static volatile int volatileInt = 3; + + public int testLoopCarriedSnippet(int iterations) { + int a = 0; + int b = 0; + int c = 0; + + for (int i = 0; branchProbability(0.99, i < iterations); i++) { + int t1 = volatileInt; + int t2 = a + b; + c = b; + b = a; + a = t1 + t2; } - return c + d; + + return c; + } + + public int testLoopCarriedReference(int iterations) { + int a = 0; + int b = 0; + int c = 0; + + for (int i = 0; branchProbability(0.99, i < iterations); i += 2) { + int t1 = volatileInt; + int t2 = a + b; + c = b; + b = a; + a = t1 + t2; + t1 = volatileInt; + t2 = a + b; + c = b; + b = a; + a = t1 + t2; + } + + return c; } public static long init = Runtime.getRuntime().totalMemory(); @@ -181,4 +182,82 @@ public void testSignExtension() { test("testSignExtensionSnippet", 9L); } + + @Override + protected Suites createSuites(OptionValues opts) { + Suites suites = super.createSuites(opts).copy(); + PhaseSuite mid = suites.getMidTier(); + ListIterator> iter = mid.findPhase(LoopPartialUnrollPhase.class); + BasePhase partialUnoll = iter.previous(); + if (iter.previous().getClass() != FrameStateAssignmentPhase.class) { + // Ensure LoopPartialUnrollPhase runs immediately after FrameStateAssignment, so it gets + // priority over other optimizations in these tests. + mid.findPhase(LoopPartialUnrollPhase.class).remove(); + ListIterator> fsa = mid.findPhase(FrameStateAssignmentPhase.class); + fsa.add(partialUnoll); + } + return suites; + } + + public void testGraph(String reference, String test) { + StructuredGraph referenceGraph = buildGraph(reference, false); + StructuredGraph testGraph = buildGraph(test, true); + assertEquals(referenceGraph, testGraph, false, false); + } + + @SuppressWarnings("try") + public StructuredGraph buildGraph(String name, boolean partialUnroll) { + CompilationIdentifier id = new CompilationIdentifier() { + @Override + public String toString(Verbosity verbosity) { + return name; + } + }; + ResolvedJavaMethod method = getResolvedJavaMethod(name); + OptionValues options = new OptionValues(getInitialOptions(), DefaultLoopPolicies.UnrollMaxIterations, 2); + StructuredGraph graph = parse(builder(method, StructuredGraph.AllowAssumptions.YES, id, options), getEagerGraphBuilderSuite()); + try (DebugContext.Scope buildScope = graph.getDebug().scope(name, method, graph)) { + MidTierContext context = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, null); + + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + new RemoveValueProxyPhase().apply(graph); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new FloatingReadPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new ConditionalEliminationPhase(true).apply(graph, context); + ComputeLoopFrequenciesClosure.compute(graph); + new GuardLoweringPhase().apply(graph, context); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); + new FrameStateAssignmentPhase().apply(graph); + new DeoptimizationGroupingPhase().apply(graph, context); + canonicalizer.apply(graph, context); + new ConditionalEliminationPhase(true).apply(graph, context); + if (partialUnroll) { + LoopsData dataCounted = new LoopsData(graph); + dataCounted.detectedCountedLoops(); + for (LoopEx loop : dataCounted.countedLoops()) { + LoopFragmentInside newSegment = loop.inside().duplicate(); + newSegment.insertWithinAfter(loop, false); + } + canonicalizer.apply(graph, getDefaultMidTierContext()); + } + new DeadCodeEliminationPhase().apply(graph); + canonicalizer.apply(graph, context); + graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "before compare"); + return graph; + } catch (Throwable e) { + throw getDebugContext().handle(e); + } + } + + public void testDuplicateBody(String reference, String test) { + + StructuredGraph referenceGraph = buildGraph(reference, false); + StructuredGraph testGraph = buildGraph(test, true); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(testGraph, getDefaultMidTierContext()); + canonicalizer.apply(referenceGraph, getDefaultMidTierContext()); + assertEquals(referenceGraph, testGraph); + } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java Tue Sep 05 10:09:44 2017 -0700 @@ -100,11 +100,12 @@ @Override public boolean shouldPartiallyUnroll(LoopEx loop) { + LoopBeginNode loopBegin = loop.loopBegin(); if (!loop.isCounted()) { + loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s isn't counted", loopBegin); return false; } OptionValues options = loop.entryPoint().getOptions(); - LoopBeginNode loopBegin = loop.loopBegin(); int maxNodes = ExactPartialUnrollMaxNodes.getValue(options); maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount())); int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); @@ -112,6 +113,7 @@ if (unrollFactor == 1) { double loopFrequency = loopBegin.loopFrequency(); if (loopBegin.isSimpleLoop() && loopFrequency < 5.0) { + loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s frequency too low %s ", loopBegin, loopFrequency); return false; } loopBegin.setLoopOrigFrequency(loopFrequency); @@ -136,6 +138,7 @@ } return true; } else { + loopBegin.getDebug().log(DebugContext.VERBOSE_LEVEL, "shouldPartiallyUnroll %s unrolled loop is too large %s ", loopBegin, size); return false; } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Tue Sep 05 10:09:44 2017 -0700 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.loop; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -142,18 +143,49 @@ end.setNext(loop.entryPoint()); } + /** + * Duplicate the body within the loop after the current copy copy of the body, updating the + * iteration limit to account for the duplication. + * + * @param loop + */ public void insertWithinAfter(LoopEx loop) { + insertWithinAfter(loop, true); + } + + /** + * Duplicate the body within the loop after the current copy copy of the body. + * + * @param loop + * @param updateLimit true if the iteration limit should be adjusted. + */ + public void insertWithinAfter(LoopEx loop, boolean updateLimit) { assert isDuplicate() && original().loop() == loop; patchNodes(dataFixWithinAfter); + /* + * Collect any new back edges values before updating them since they might reference each + * other. + */ LoopBeginNode mainLoopBegin = loop.loopBegin(); + ArrayList backedgeValues = new ArrayList<>(); for (PhiNode mainPhiNode : mainLoopBegin.phis()) { ValueNode duplicatedNode = getDuplicatedNode(mainPhiNode.valueAt(1)); + if (duplicatedNode == null) { + if (mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1))) { + duplicatedNode = ((PhiNode) (mainPhiNode.valueAt(1))).valueAt(1); + } else { + assert mainPhiNode.valueAt(1).isConstant() : mainPhiNode.valueAt(1); + } + } + backedgeValues.add(duplicatedNode); + } + int index = 0; + for (PhiNode mainPhiNode : mainLoopBegin.phis()) { + ValueNode duplicatedNode = backedgeValues.get(index++); if (duplicatedNode != null) { mainPhiNode.setValueAt(1, duplicatedNode); - } else { - assert mainPhiNode.valueAt(1).isConstant() || mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1)) : mainPhiNode.valueAt(1); } } @@ -166,27 +198,29 @@ } int unrollFactor = mainLoopBegin.getUnrollFactor(); - - // Now use the previous unrollFactor to update the exit condition to power of two StructuredGraph graph = mainLoopBegin.graph(); - InductionVariable iv = loop.counted().getCounter(); - CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition(); - ValueNode compareBound; - if (compareNode.getX() == iv.valueNode()) { - compareBound = compareNode.getY(); - } else if (compareNode.getY() == iv.valueNode()) { - compareBound = compareNode.getX(); - } else { - throw GraalError.shouldNotReachHere(); - } - if (iv.direction() == InductionVariable.Direction.Up) { - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * iv.constantStride())); - ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); - } else if (iv.direction() == InductionVariable.Direction.Down) { - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * -iv.constantStride())); - ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); + if (updateLimit) { + // Now use the previous unrollFactor to update the exit condition to power of two + InductionVariable iv = loop.counted().getCounter(); + CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition(); + ValueNode compareBound; + if (compareNode.getX() == iv.valueNode()) { + compareBound = compareNode.getY(); + } else if (compareNode.getY() == iv.valueNode()) { + compareBound = compareNode.getX(); + } else { + throw GraalError.shouldNotReachHere(); + } + long originalStride = unrollFactor == 1 ? iv.constantStride() : iv.constantStride() / unrollFactor; + if (iv.direction() == InductionVariable.Direction.Up) { + ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * originalStride)); + ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal)); + compareNode.replaceFirstInput(compareBound, newLimit); + } else if (iv.direction() == InductionVariable.Direction.Down) { + ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(), unrollFactor * -originalStride)); + ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal)); + compareNode.replaceFirstInput(compareBound, newLimit); + } } mainLoopBegin.setUnrollFactor(unrollFactor * 2); mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMH.java Sun Sep 03 19:31:11 2017 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.microbenchmarks.graal; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Warmup; - -@Warmup(iterations = 1) -@Measurement(iterations = 1) -@Fork(1) -/** - * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly. - */ -public class TestJMH { - - @Benchmark - public void testJMH() { - // This method was intentionally left blank. - } - -} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,44 @@ +/* + * 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. + */ +package org.graalvm.compiler.microbenchmarks.graal; + +import org.graalvm.compiler.microbenchmarks.graal.util.GraalState; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Warmup; + +@Warmup(iterations = 1) +@Measurement(iterations = 1) +@Fork(1) +/** + * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly. + */ +public class TestJMHWhitebox { + + @Benchmark + public void testJMH(@SuppressWarnings("unused") GraalState s) { + // This method was intentionally left blank. + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,12 +25,10 @@ import static org.graalvm.compiler.core.test.GraalCompilerTest.getInitialOptions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import org.junit.Before; -import org.junit.Test; +import java.math.BigInteger; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp; import org.graalvm.compiler.core.common.type.IntegerStamp; @@ -42,6 +40,12 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.options.OptionValues; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; /** * This class tests that integer stamps are created correctly for constants. @@ -365,10 +369,187 @@ assertEquals(IntegerStamp.create(32, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); assertEquals(IntegerStamp.create(32, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); assertEquals(IntegerStamp.create(32, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(32, -4096, -4096, -4096, -4096), shl.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Int), shl.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Int), shl.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); assertEquals(IntegerStamp.create(64, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); assertEquals(IntegerStamp.create(64, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); assertEquals(IntegerStamp.create(64, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(64, -4096, -4096, -4096, -4096), shl.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Long), shl.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Long), shl.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); + } + @Test + public void testUnsignedShiftRight() { + ShiftOp ushr = IntegerStamp.OPS.getUShr(); + assertEquals(IntegerStamp.create(32, 0, 0xff, 0, 0xff), ushr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); + assertEquals(IntegerStamp.create(32, 0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(32, 0x0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(32, 0xffffff, 0xffffff, 0xffffff, 0xffffff), ushr.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Int), ushr.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Int), ushr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); + + assertEquals(IntegerStamp.create(64, 0, 0xff, 0, 0xff), ushr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); + assertEquals(IntegerStamp.create(64, 0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(64, 0x0, 0x07, 0, 0x07), ushr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(64, 0xffffffffffffffL, 0xffffffffffffffL, 0xffffffffffffffL, 0xffffffffffffffL), + ushr.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Long), ushr.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Long), ushr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); + } + + @Test + public void testShiftRight() { + ShiftOp shr = IntegerStamp.OPS.getShr(); + assertEquals(IntegerStamp.create(32, 0, 0xff, 0, 0xff), shr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); + assertEquals(IntegerStamp.create(32, 0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(32, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(32, 0x0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(32, -1, -1, -1, -1), shr.foldStamp(IntegerStamp.create(32, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Int), shr.foldStamp(StampFactory.empty(JavaKind.Int), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Int), shr.foldStamp(IntegerStamp.create(32, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); + + assertEquals(IntegerStamp.create(64, 0, 0xff, 0, 0xff), shr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 0, 1, 0, 1))); + assertEquals(IntegerStamp.create(64, 0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(64, 0, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(64, 0x0, 0x07, 0, 0x07), shr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(IntegerStamp.create(64, -1, -1, -1, -1), shr.foldStamp(IntegerStamp.create(64, -16, -16, -16, -16), IntegerStamp.create(32, 8, 8, 8, 8))); + assertEquals(StampFactory.empty(JavaKind.Long), shr.foldStamp(StampFactory.empty(JavaKind.Long), IntegerStamp.create(32, 5, 5, 5, 5))); + assertEquals(StampFactory.empty(JavaKind.Long), shr.foldStamp(IntegerStamp.create(64, 0xf, 0xff, 0, 0xff), (IntegerStamp) StampFactory.empty(JavaKind.Int))); + } + + @Test + public void testMulHigh() { + testSomeMulHigh(IntegerStamp.OPS.getMulHigh()); + } + + @Test + public void testUMulHigh() { + testSomeMulHigh(IntegerStamp.OPS.getUMulHigh()); + } + + private static void testSomeMulHigh(BinaryOp someMulHigh) { + // 32 bits + testMulHigh(someMulHigh, 0, 0, 32); + + testMulHigh(someMulHigh, 1, 1, 32); + testMulHigh(someMulHigh, 1, 5, 32); + testMulHigh(someMulHigh, 256, 256, 32); + testMulHigh(someMulHigh, 0xFFFFFFF, 0xFFFFFFA, 32); + testMulHigh(someMulHigh, Integer.MAX_VALUE, 2, 32); + + testMulHigh(someMulHigh, -1, -1, 32); + testMulHigh(someMulHigh, -1, -5, 32); + testMulHigh(someMulHigh, -256, -256, 32); + testMulHigh(someMulHigh, -0xFFFFFFF, -0xFFFFFFA, 32); + testMulHigh(someMulHigh, Integer.MIN_VALUE, -2, 32); + + testMulHigh(someMulHigh, -1, 1, 32); + testMulHigh(someMulHigh, -1, 5, 32); + testMulHigh(someMulHigh, -256, 256, 32); + testMulHigh(someMulHigh, -0xFFFFFFF, 0xFFFFFFA, 32); + testMulHigh(someMulHigh, Integer.MIN_VALUE, 2, 32); + + testMulHigh(someMulHigh, Integer.MIN_VALUE, Integer.MIN_VALUE, 32); + testMulHigh(someMulHigh, Integer.MAX_VALUE, Integer.MAX_VALUE, 32); + + assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), StampFactory.forKind(JavaKind.Int).empty())); + assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), StampFactory.forKind(JavaKind.Int).unrestricted())); + assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, 0, 0))); + assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, 1, 1))); + assertEquals(StampFactory.forKind(JavaKind.Int).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).empty(), IntegerStamp.create(32, -1, -1))); + + assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), StampFactory.forKind(JavaKind.Int).unrestricted())); + assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, 0, 0))); + assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, 1, 1))); + assertEquals(StampFactory.forKind(JavaKind.Int).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Int).unrestricted(), IntegerStamp.create(32, -1, -1))); + + // 64 bits + testMulHigh(someMulHigh, 0, 0, 64); + + testMulHigh(someMulHigh, 1, 1, 64); + testMulHigh(someMulHigh, 1, 5, 64); + testMulHigh(someMulHigh, 256, 256, 64); + testMulHigh(someMulHigh, 0xFFFFFFF, 0xFFFFFFA, 64); + testMulHigh(someMulHigh, 0xFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFAL, 64); + testMulHigh(someMulHigh, Integer.MAX_VALUE, 2, 64); + testMulHigh(someMulHigh, Long.MAX_VALUE, 2, 64); + + testMulHigh(someMulHigh, -1, -1, 64); + testMulHigh(someMulHigh, -1, -5, 64); + testMulHigh(someMulHigh, -256, -256, 64); + testMulHigh(someMulHigh, -0xFFFFFFF, -0xFFFFFFA, 64); + testMulHigh(someMulHigh, -0xFFFFFFFFFFFFFFL, -0xFFFFFFFFFFFFFAL, 64); + testMulHigh(someMulHigh, Integer.MIN_VALUE, -2, 64); + testMulHigh(someMulHigh, Long.MIN_VALUE, -2, 64); + + testMulHigh(someMulHigh, -1, 1, 64); + testMulHigh(someMulHigh, -1, 5, 64); + testMulHigh(someMulHigh, -256, 256, 64); + testMulHigh(someMulHigh, -0xFFFFFFF, 0xFFFFFFA, 64); + testMulHigh(someMulHigh, -0xFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFAL, 64); + testMulHigh(someMulHigh, Integer.MIN_VALUE, 2, 64); + testMulHigh(someMulHigh, Long.MIN_VALUE, 2, 64); + + testMulHigh(someMulHigh, Integer.MIN_VALUE, Integer.MIN_VALUE, 64); + testMulHigh(someMulHigh, Long.MIN_VALUE, Long.MIN_VALUE, 64); + testMulHigh(someMulHigh, Integer.MAX_VALUE, Integer.MAX_VALUE, 64); + testMulHigh(someMulHigh, Long.MAX_VALUE, Long.MAX_VALUE, 64); + + assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), StampFactory.forKind(JavaKind.Long).empty())); + assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), StampFactory.forKind(JavaKind.Long).unrestricted())); + assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, 0, 0))); + assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, 1, 1))); + assertEquals(StampFactory.forKind(JavaKind.Long).empty(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).empty(), IntegerStamp.create(64, -1, -1))); + + assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), StampFactory.forKind(JavaKind.Long).unrestricted())); + assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, 0, 0))); + assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, 1, 1))); + assertEquals(StampFactory.forKind(JavaKind.Long).unrestricted(), someMulHigh.foldStamp(StampFactory.forKind(JavaKind.Long).unrestricted(), IntegerStamp.create(64, -1, -1))); + } + + private static void testMulHigh(BinaryOp someMulHigh, long a, long b, int bits) { + long expectedResult = getExpectedValue(someMulHigh, a, b, bits); + assertEquals(IntegerStamp.create(bits, expectedResult, expectedResult), someMulHigh.foldStamp(IntegerStamp.create(bits, a, a), IntegerStamp.create(bits, b, b))); + } + + private static long getExpectedValue(BinaryOp someMulHigh, long a, long b, int bits) { + if (someMulHigh == IntegerStamp.OPS.getMulHigh()) { + return mulHigh(a, b, bits); + } else { + assertEquals(IntegerStamp.OPS.getUMulHigh(), someMulHigh); + return umulHigh(a, b, bits); + } + } + + private static long mulHigh(long a, long b, int bits) { + BigInteger valA = BigInteger.valueOf(a); + BigInteger valB = BigInteger.valueOf(b); + BigInteger result = valA.multiply(valB).shiftRight(bits); + if (bits == 32) { + return result.intValue(); + } else { + assertEquals(64, bits); + return result.longValue(); + } + } + + private static long umulHigh(long a, long b, int bits) { + Assert.assertTrue(bits == 32 || bits == 64); + BigInteger valA = BigInteger.valueOf(a); + if (valA.compareTo(BigInteger.valueOf(0)) < 0) { + valA = valA.add(BigInteger.ONE.shiftLeft(bits)); + } + BigInteger valB = BigInteger.valueOf(b); + if (valB.compareTo(BigInteger.valueOf(0)) < 0) { + valB = valB.add(BigInteger.ONE.shiftLeft(bits)); + } + + BigInteger result = valA.multiply(valB).shiftRight(bits); + if (bits == 32) { + return result.intValue(); + } else { + return result.longValue(); + } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Tue Sep 05 10:09:44 2017 -0700 @@ -466,6 +466,28 @@ AbstractMergeNode merge = (AbstractMergeNode) node; EndNode singleEnd = merge.forwardEndAt(0); + /* + * In some corner cases, the MergeNode already has PhiNodes. Since there is a single + * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with + * this single input. + */ + for (PhiNode phi : merge.phis()) { + assert phi.inputs().count() == 1 : "input count must match end count"; + Node singlePhiInput = phi.inputs().first(); + + /* + * We do not have the orderID of the PhiNode anymore, so we need to search through + * the complete list of nodes to find a match. + */ + for (int i = 0; i < loopScope.createdNodes.length; i++) { + if (loopScope.createdNodes[i] == phi) { + loopScope.createdNodes[i] = singlePhiInput; + } + } + + phi.replaceAndDelete(singlePhiInput); + } + /* Nodes that would use this merge as the guard need to use the previous block. */ registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul; import org.graalvm.compiler.core.common.type.Stamp; @@ -108,6 +109,27 @@ return AddNode.create(new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i - 1))), forX); } else if (CodeUtil.isPowerOf2(i + 1)) { return SubNode.create(new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i + 1))), forX); + } else { + int bitCount = Long.bitCount(i); + long highestBitValue = Long.highestOneBit(i); + if (bitCount == 2) { + // e.g., 0b1000_0010 + long lowerBitValue = i - highestBitValue; + assert highestBitValue > 0 && lowerBitValue > 0; + ValueNode left = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(highestBitValue))); + ValueNode right = lowerBitValue == 1 ? forX : new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(lowerBitValue))); + return AddNode.create(left, right); + } else { + // e.g., 0b1111_1101 + int shiftToRoundUpToPowerOf2 = CodeUtil.log2(highestBitValue) + 1; + long subValue = (1 << shiftToRoundUpToPowerOf2) - i; + if (CodeUtil.isPowerOf2(subValue) && shiftToRoundUpToPowerOf2 < ((IntegerStamp) stamp).getBits()) { + assert CodeUtil.log2(subValue) >= 1; + ValueNode left = new LeftShiftNode(forX, ConstantNode.forInt(shiftToRoundUpToPowerOf2)); + ValueNode right = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(subValue))); + return SubNode.create(left, right); + } + } } } else if (i < 0) { if (CodeUtil.isPowerOf2(-i)) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Tue Sep 05 10:09:44 2017 -0700 @@ -562,7 +562,7 @@ if (pred.getSuccessorCount() > 1) { assert pred.getEndNode() instanceof ControlSplitNode; ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode(); - probability *= controlSplit.probability(block.getBeginNode()); + probability = multiplyProbabilities(probability, controlSplit.probability(block.getBeginNode())); } } else { probability = predecessors[0].probability; @@ -572,7 +572,7 @@ if (block.getBeginNode() instanceof LoopBeginNode) { LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode(); - probability *= loopBegin.loopFrequency(); + probability = multiplyProbabilities(probability, loopBegin.loopFrequency()); } } if (probability < MIN_PROBABILITY) { @@ -755,4 +755,20 @@ public void setNodeToBlock(NodeMap nodeMap) { this.nodeToBlock = nodeMap; } + + /** + * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_PROBABILITY} and + * {@link ControlFlowGraph#MAX_PROBABILITY}. + */ + public static double multiplyProbabilities(double a, double b) { + assert !Double.isNaN(a) && !Double.isNaN(b) && Double.isFinite(a) && Double.isFinite(b) : a + " " + b; + double r = a * b; + if (r > MAX_PROBABILITY) { + return MAX_PROBABILITY; + } + if (r < MIN_PROBABILITY) { + return MIN_PROBABILITY; + } + return r; + } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Tue Sep 05 10:09:44 2017 -0700 @@ -22,9 +22,12 @@ */ package org.graalvm.compiler.options.processor; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -50,7 +53,9 @@ import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptor; @@ -117,22 +122,13 @@ return; } - String help = annotation.help(); - if (help.length() != 0) { - char firstChar = help.charAt(0); - if (!Character.isUpperCase(firstChar)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element); - return; - } - } - String optionName = annotation.name(); if (optionName.equals("")) { optionName = fieldName; } if (!Character.isUpperCase(optionName.charAt(0))) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option name must start with capital letter", element); + processingEnv.getMessager().printMessage(Kind.ERROR, "Option name must start with an upper case letter", element); return; } @@ -154,6 +150,7 @@ String separator = ""; Set originatingElementsList = info.originatingElements; originatingElementsList.add(field); + PackageElement enclosingPackage = null; while (enclosing != null) { if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { @@ -164,13 +161,64 @@ originatingElementsList.add(enclosing); declaringClass = enclosing.getSimpleName() + separator + declaringClass; separator = "."; - } else { - assert enclosing.getKind() == ElementKind.PACKAGE; + } else if (enclosing.getKind() == ElementKind.PACKAGE) { + enclosingPackage = (PackageElement) enclosing; } enclosing = enclosing.getEnclosingElement(); } + if (enclosingPackage == null) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be declared in the unnamed package", element); + return; + } + String[] helpValue = annotation.help(); + String help = ""; + String[] extraHelp = {}; - info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field)); + if (helpValue.length == 1) { + help = helpValue[0]; + if (help.startsWith("file:")) { + String path = help.substring("file:".length()); + Filer filer = processingEnv.getFiler(); + try { + FileObject file; + try { + file = filer.getResource(StandardLocation.SOURCE_PATH, enclosingPackage.getQualifiedName(), path); + } catch (IllegalArgumentException | IOException e) { + // Handle the case when a compiler doesn't support the SOURCE_PATH location + file = filer.getResource(StandardLocation.CLASS_OUTPUT, enclosingPackage.getQualifiedName(), path); + } + try (BufferedReader br = new BufferedReader(new InputStreamReader(file.openInputStream()))) { + help = br.readLine(); + if (help == null) { + help = ""; + } + String line = br.readLine(); + List lines = new ArrayList<>(); + while (line != null) { + lines.add(line); + line = br.readLine(); + } + extraHelp = lines.toArray(new String[lines.size()]); + } + } catch (IOException e) { + String msg = String.format("Error reading %s containing the help text for option field: %s", path, e); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + } + } else if (helpValue.length > 1) { + help = helpValue[0]; + extraHelp = Arrays.copyOfRange(helpValue, 1, helpValue.length); + } + if (help.length() != 0) { + char firstChar = help.charAt(0); + if (!Character.isUpperCase(firstChar)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with an upper case letter", element); + return; + } + } + + info.options.add(new OptionInfo(optionName, help, extraHelp, optionType, declaringClass, field)); } private void createFiles(OptionsInfo info) { @@ -200,11 +248,11 @@ String desc = OptionDescriptor.class.getSimpleName(); - int i = 0; Collections.sort(info.options); out.println(" @Override"); out.println(" public OptionDescriptor get(String value) {"); + out.println(" switch (value) {"); out.println(" // CheckStyle: stop line length check"); for (OptionInfo option : info.options) { String name = option.name; @@ -214,41 +262,52 @@ } else { optionField = option.declaringClass + "." + option.field.getSimpleName(); } + out.println(" case \"" + name + "\": {"); String type = option.type; String help = option.help; + String[] extraHelp = option.extraHelp; String declaringClass = option.declaringClass; Name fieldName = option.field.getSimpleName(); - out.println(" if (value.equals(\"" + name + "\")) {"); - out.printf(" return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionField); + out.printf(" return " + desc + ".create(\n"); + out.printf(" /*name*/ \"%s\",\n", name); + out.printf(" /*type*/ %s.class,\n", type); + out.printf(" /*help*/ \"%s\",\n", help); + if (extraHelp.length != 0) { + out.printf(" /*extraHelp*/ new String[] {\n"); + for (String line : extraHelp) { + out.printf(" \"%s\",\n", line.replace("\\", "\\\\").replace("\"", "\\\"")); + } + out.printf(" },\n"); + } + out.printf(" /*declaringClass*/ %s.class,\n", declaringClass); + out.printf(" /*fieldName*/ \"%s\",\n", fieldName); + out.printf(" /*option*/ %s);\n", optionField); out.println(" }"); } out.println(" // CheckStyle: resume line length check"); + out.println(" }"); out.println(" return null;"); out.println(" }"); out.println(); out.println(" @Override"); out.println(" public Iterator<" + desc + "> iterator() {"); - out.println(" // CheckStyle: stop line length check"); - out.println(" List<" + desc + "> options = Arrays.asList("); - for (OptionInfo option : info.options) { - String optionField; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - throw new InternalError(); - } else { - optionField = option.declaringClass + "." + option.field.getSimpleName(); - } - String name = option.name; - String type = option.type; - String help = option.help; - String declaringClass = option.declaringClass; - Name fieldName = option.field.getSimpleName(); - String comma = i == info.options.size() - 1 ? "" : ","; - out.printf(" %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionField, comma); - i++; + out.println(" return new Iterator() {"); + out.println(" int i = 0;"); + out.println(" @Override"); + out.println(" public boolean hasNext() {"); + out.println(" return i < " + info.options.size() + ";"); + out.println(" }"); + out.println(" @Override"); + out.println(" public OptionDescriptor next() {"); + out.println(" switch (i++) {"); + for (int i = 0; i < info.options.size(); i++) { + OptionInfo option = info.options.get(i); + out.println(" case " + i + ": return get(\"" + option.name + "\");"); } - out.println(" );"); - out.println(" // CheckStyle: resume line length check"); - out.println(" return options.iterator();"); + out.println(" }"); + out.println(" throw new NoSuchElementException();"); + out.println(" }"); + out.println(" };"); out.println(" }"); out.println("}"); } @@ -274,13 +333,15 @@ final String name; final String help; + final String[] extraHelp; final String type; final String declaringClass; final VariableElement field; - OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { + OptionInfo(String name, String help, String[] extraHelp, String type, String declaringClass, VariableElement field) { this.name = name; this.help = help; + this.extraHelp = extraHelp; this.type = type; this.declaringClass = declaringClass; this.field = field; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java Tue Sep 05 10:09:44 2017 -0700 @@ -28,27 +28,10 @@ public class EnumOptionKey> extends OptionKey { final Class enumClass; - final ValueHelp valueHelp; - - /** - * Provides help text for enum values. - */ - public interface ValueHelp> { - /** - * Gets help text for the enum {@code value} that includes the name of the value. If - * {@code null} is returned, {@code value.toString()} is used. - */ - String getHelp(Object value); - } - - public EnumOptionKey(T value) { - this(value, null); - } @SuppressWarnings("unchecked") - public EnumOptionKey(T value, ValueHelp help) { + public EnumOptionKey(T value) { super(value); - this.valueHelp = help; if (value == null) { throw new IllegalArgumentException("Value must not be null"); } @@ -62,10 +45,6 @@ return EnumSet.allOf(enumClass); } - public ValueHelp getValueHelp() { - return valueHelp; - } - Object valueOf(String name) { try { return Enum.valueOf(enumClass, name); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java Tue Sep 05 10:09:44 2017 -0700 @@ -38,10 +38,20 @@ public @interface Option { /** - * Gets a help message for the option. New lines can be embedded in the message with - * {@code "%n"}. + * Gets a help message for the option. + *

+ * The first element of the array is the short help message. This part of the help message is + * subject to line wrapping when printed. + *

+ * The remaining elements contain a more detailed expansion of the help message and will be + * printed as is in a left-aligned block (i.e. leading spaces will be preserved). + *

+ * If there is only one element and it starts with {@code "file:"}, then the help message + * is located in a file located by resolving {@code } against the location of the package + * in which the option is declared. The first line in the file is the short help message as + * described above. The remaining lines are the help message expansion. */ - String help(); + String[] help(); /** * The name of the option. By default, the name of the annotated field should be used. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java Tue Sep 05 10:09:44 2017 -0700 @@ -22,6 +22,10 @@ */ package org.graalvm.compiler.options; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * Describes the attributes of a static field {@linkplain Option option} and provides access to its * {@linkplain OptionKey value}. @@ -31,25 +35,34 @@ protected final String name; protected final Class type; protected final String help; + protected final List extraHelp; protected final OptionKey optionKey; protected final Class declaringClass; protected final String fieldName; + private static final String[] NO_EXTRA_HELP = {}; + public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionKey option) { + return create(name, type, help, NO_EXTRA_HELP, declaringClass, fieldName, option); + } + + public static OptionDescriptor create(String name, Class type, String help, String[] extraHelp, Class declaringClass, String fieldName, OptionKey option) { assert option != null : declaringClass + "." + fieldName; OptionDescriptor result = option.getDescriptor(); if (result == null) { - result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option); + List extraHelpList = extraHelp == null || extraHelp.length == 0 ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(extraHelp)); + result = new OptionDescriptor(name, type, help, extraHelpList, declaringClass, fieldName, option); option.setDescriptor(result); } assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.optionKey == option; return result; } - private OptionDescriptor(String name, Class type, String help, Class declaringClass, String fieldName, OptionKey optionKey) { + private OptionDescriptor(String name, Class type, String help, List extraHelp, Class declaringClass, String fieldName, OptionKey optionKey) { this.name = name; this.type = type; this.help = help; + this.extraHelp = extraHelp; this.optionKey = optionKey; this.declaringClass = declaringClass; this.fieldName = fieldName; @@ -65,13 +78,24 @@ } /** - * Gets a descriptive help message for the option. + * Gets a descriptive help message for the option. This message should be self contained without + * relying on {@link #getExtraHelp() extra help lines}. + * + * @see Option#help() */ public String getHelp() { return help; } /** + * Gets extra lines of help text. These lines should not be subject to any line wrapping or + * formatting apart from indentation. + */ + public List getExtraHelp() { + return extraHelp; + } + + /** * Gets the name of the option. It's up to the client of this object how to use the name to get * a user specified value for the option from the environment. */ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,15 +24,12 @@ import java.io.PrintStream; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; -import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import org.graalvm.compiler.options.EnumOptionKey.ValueHelp; import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence; import org.graalvm.util.UnmodifiableEconomicMap; @@ -165,10 +162,9 @@ * @return {@code text} broken into lines */ private static List wrap(String text, int width) { - List lines = Collections.singletonList(text); + List lines = new ArrayList<>(); if (text.length() > width) { String[] chunks = text.split("\\s+"); - lines = new ArrayList<>(); StringBuilder line = new StringBuilder(); for (String chunk : chunks) { if (line.length() + chunk.length() > width) { @@ -178,22 +174,13 @@ if (line.length() != 0) { line.append(' '); } - String[] embeddedLines = chunk.split("%n", -2); - if (embeddedLines.length == 1) { - line.append(chunk); - } else { - for (int i = 0; i < embeddedLines.length; i++) { - line.append(embeddedLines[i]); - if (i < embeddedLines.length - 1) { - lines.add(line.toString()); - line.setLength(0); - } - } - } + line.append(chunk); } if (line.length() != 0) { lines.add(line.toString()); } + } else { + lines.add(text); } return lines; } @@ -222,24 +209,7 @@ if (value instanceof String) { value = '"' + String.valueOf(value) + '"'; } - String help = desc.getHelp(); - if (desc.getOptionKey() instanceof EnumOptionKey) { - EnumOptionKey eoption = (EnumOptionKey) desc.getOptionKey(); - EnumSet evalues = eoption.getAllValues(); - String evaluesString = evalues.toString(); - ValueHelp valueHelp = eoption.getValueHelp(); - if (help.length() > 0 && !help.endsWith(".")) { - help += "."; - } - if (valueHelp == null) { - help += " Valid values are: " + evaluesString.substring(1, evaluesString.length() - 1); - } else { - for (Object o : evalues) { - String vhelp = valueHelp.getHelp(o); - help += "%n" + (vhelp == null ? o : vhelp); - } - } - } + String name = namePrefix + e.getKey(); String assign = containsKey(desc.optionKey) ? ":=" : "="; String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getType().getSimpleName(); @@ -252,11 +222,16 @@ out.printf("%s[%s]%n", linePrefix, typeName); } + List helpLines; + String help = desc.getHelp(); if (help.length() != 0) { - List helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT); - for (int i = 0; i < helpLines.size(); i++) { - out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", helpLines.get(i)); - } + helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT); + helpLines.addAll(desc.getExtraHelp()); + } else { + helpLines = desc.getExtraHelp(); + } + for (String line : helpLines) { + out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line); } } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Tue Sep 05 10:09:44 2017 -0700 @@ -30,6 +30,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import org.graalvm.compiler.api.replacements.MethodSubstitution; @@ -351,7 +352,7 @@ } } - updateSourcePositions(invoke, inlineGraph, duplicates); + updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod)); if (stateAfter != null) { processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1); int callerLockDepth = stateAfter.nestedLockDepth(); @@ -569,14 +570,14 @@ } @SuppressWarnings("try") - private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap duplicates) { + private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap duplicates, boolean isSubstitution) { if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) { if (invoke.asNode().getNodeSourcePosition() == null) { // Temporarily ignore the assert below. return; } - JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() ? invoke.getReceiver().asJavaConstant() : null; + JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() && !isSubstitution ? invoke.getReceiver().asJavaConstant() : null; NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition(); assert invokePos != null : "missing source information"; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/AbstractInliningPolicy.java Tue Sep 05 10:09:44 2017 -0700 @@ -75,10 +75,11 @@ } private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) { - for (int i = 0; i < info.numberOfMethods(); i++) { - if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) { - return false; - } + if (!onlyIntrinsics(replacements, info)) { + return false; + } + if (!info.shouldInline()) { + return false; } return true; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java Tue Sep 05 10:09:44 2017 -0700 @@ -39,6 +39,8 @@ import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; + /** * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s. */ @@ -106,7 +108,7 @@ } } else { ControlSplitNode split = (ControlSplitNode) current.predecessor(); - probability = split.probability((AbstractBeginNode) current) * applyAsDouble(split); + probability = multiplyProbabilities(split.probability((AbstractBeginNode) current), applyAsDouble(split)); } assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability; cache.put(current, probability); @@ -125,7 +127,7 @@ result += applyAsDouble(endNode); } if (current instanceof LoopBeginNode) { - result *= ((LoopBeginNode) current).loopFrequency(); + result = multiplyProbabilities(result, ((LoopBeginNode) current).loopFrequency()); } return result; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Tue Sep 05 10:09:44 2017 -0700 @@ -366,7 +366,7 @@ return ((Class) obj).getName(); } if (obj instanceof ResolvedJavaType) { - return ((ResolvedJavaType) obj).getName(); + return ((ResolvedJavaType) obj).toJavaName(); } return null; } @@ -403,7 +403,7 @@ @Override public String fieldTypeName(ResolvedJavaField field) { - return field.getType().getName(); + return field.getType().toJavaName(); } @Override diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java Tue Sep 05 10:09:44 2017 -0700 @@ -31,6 +31,8 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import java.util.Arrays; + import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode; import org.graalvm.compiler.nodes.ValueNode; @@ -44,6 +46,7 @@ import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.replacements.ArraysSubstitutions; import org.graalvm.compiler.replacements.IntegerSubstitutions; import org.graalvm.compiler.replacements.LongSubstitutions; import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeGetPlugin; @@ -73,6 +76,7 @@ registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider); registerStringPlugins(invocationPlugins, arch, replacementsBytecodeProvider); registerMathPlugins(invocationPlugins, arch, arithmeticStubs, replacementsBytecodeProvider); + registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider); } }); } @@ -229,4 +233,10 @@ r.registerOptional4("put" + kind.name() + "Unaligned", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false)); } } + + private static void registerArraysEqualsPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, Arrays.class, bytecodeProvider); + r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class); + r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class); + } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -232,68 +232,6 @@ } @Test - public void testEqualsFloat() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new float[i]; - args2[n] = new float[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - float[] a2 = new float[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new float[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{float[].class, float[].class}; - testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsFloat(float[] a, float[] b) { - return Arrays.equals(a, b); - } - - @Test - public void testEqualsDouble() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new double[i]; - args2[n] = new double[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - double[] a2 = new double[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new double[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{double[].class, double[].class}; - testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsDouble(double[] a, double[] b) { - return Arrays.equals(a, b); - } - - @Test public void testEqualsNodeGVN() { test("testEqualsNodeGVNSnippet", true); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -24,16 +24,25 @@ import java.util.Random; +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.phases.HighTier; import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.AbstractInliningPhase; import org.graalvm.compiler.test.ExportingClassLoader; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -90,6 +99,61 @@ return "SUCCESS"; } + @Test + public void test3() { + Assume.assumeTrue("Only works on jdk8 right now", Java8OrEarlier); + ResolvedJavaMethod method = getResolvedJavaMethod("test3Snippet"); + + for (int i = 0; i < 2; i++) { + Result actual; + boolean expectedCompiledCode = (method.getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.NotCompiledExceptionHandler) != 0); + InstalledCode code = getCode(method, null, false, true, new OptionValues(getInitialOptions(), HighTier.Options.Inline, false)); + assertTrue(code.isValid()); + + try { + actual = new Result(code.executeVarargs(false), null); + } catch (Exception e) { + actual = new Result(null, e); + } + + assertTrue(i > 0 == expectedCompiledCode, "expect compiled code to stay around after the first iteration"); + assertEquals(new Result(expectedCompiledCode, null), actual); + assertTrue(expectedCompiledCode == code.isValid()); + } + } + + @Override + protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (method.getName().equals("throwException")) { + if (b.getMethod().getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.NotCompiledExceptionHandler) != 0) { + return InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; + } else { + return InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; + } + } + return super.bytecodeParserShouldInlineInvoke(b, method, args); + } + + private static void throwException() throws Exception { + throw new Exception(); + } + + static int footprint; + + public static boolean test3Snippet(boolean rethrowException) throws Exception { + try { + footprint = 1; + throwException(); + } catch (Exception e) { + footprint = 2; + if (rethrowException) { + throw e; + } + } + + return GraalDirectives.inCompiledCode(); + } + public static class MyClassLoader extends ExportingClassLoader { @Override protected Class findClass(String className) throws ClassNotFoundException { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FloatArraysEqualsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FloatArraysEqualsTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017, 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. + */ +package org.graalvm.compiler.replacements.test; + +import java.util.Arrays; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.junit.Test; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class FloatArraysEqualsTest extends GraalCompilerTest { + + public static boolean testFloatArraySnippet(float[] a, float[] b) { + return Arrays.equals(a, b); + } + + private void testEqualInFloatArray(int arraySize, int index, float f1, float f2) { + if (arraySize > 0 && index >= 0 && index < arraySize) { + float[] a1 = new float[arraySize]; + float[] a2 = new float[arraySize]; + a1[index] = f1; + a2[index] = f2; + test("testFloatArraySnippet", a1, a2); + } + } + + public static final int FLOAT_TAIL = 1; + public static final int FLOAT_8BYTE_ALIGNED = 2; + public static final int FLOAT_8BYTE_UNALIGNED = 3; + public static final int FLOAT_VECTOR_ALIGNED = 8; + public static final int FLOAT_VECTOR_UNALIGNED = 9; + + @Test + public void testFloatArray() { + for (int size : new int[]{FLOAT_TAIL, FLOAT_8BYTE_ALIGNED, FLOAT_8BYTE_UNALIGNED, FLOAT_VECTOR_ALIGNED, FLOAT_VECTOR_UNALIGNED}) { + for (int index : new int[]{0, size - 1}) { + testEqualInFloatArray(size, index, 1024, 1024); + testEqualInFloatArray(size, index, 0.0f, -0.0f); + testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), Float.intBitsToFloat(0x7fc00000)); + testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), Float.intBitsToFloat(0x7f800001)); + testEqualInFloatArray(size, index, Float.intBitsToFloat(0x7fc00000), 1024); + } + } + } + + public static boolean testDoubleArraySnippet(double[] a, double[] b) { + return Arrays.equals(a, b); + } + + public static final int DOUBLE_8BYTE_ALIGNED = 1; + public static final int DOUBLE_VECTOR_ALIGNED = 4; + public static final int DOUBLE_VECTOR_UNALIGNED = 5; + + private void testEqualInDoubleArray(int arraySize, int index, double d1, double d2) { + if (arraySize > 0 && index >= 0 && index < arraySize) { + double[] a1 = new double[arraySize]; + double[] a2 = new double[arraySize]; + a1[index] = d1; + a2[index] = d2; + test("testDoubleArraySnippet", a1, a2); + } + } + + @Test + public void testDoubleArrayOrdinary() { + for (int size : new int[]{DOUBLE_8BYTE_ALIGNED, DOUBLE_VECTOR_ALIGNED, DOUBLE_VECTOR_UNALIGNED}) { + for (int index : new int[]{0, size - 1}) { + testEqualInDoubleArray(size, index, 1024, 1024); + testEqualInDoubleArray(size, index, 0.0d, -0.0d); + testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), Double.longBitsToDouble(0x7ff8000000000000L)); + testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), Double.longBitsToDouble(0x7ff0000000000001L)); + testEqualInDoubleArray(size, index, Double.longBitsToDouble(0x7ff8000000000000L), 1024); + } + } + } + + public static boolean testFloatArrayWithPEASnippet0() { + return Arrays.equals(new float[]{0.0f}, new float[]{-0.0f}); + } + + public static boolean testFloatArrayWithPEASnippet1() { + return Arrays.equals(new float[]{Float.intBitsToFloat(0x7fc00000)}, new float[]{Float.intBitsToFloat(0x7fc00000)}); + } + + public static boolean testFloatArrayWithPEASnippet2() { + return Arrays.equals(new float[]{Float.intBitsToFloat(0x7fc00000)}, new float[]{Float.intBitsToFloat(0x7f800001)}); + + } + + @Test + public void testFloatArrayWithPEA() { + test("testFloatArrayWithPEASnippet0"); + test("testFloatArrayWithPEASnippet1"); + test("testFloatArrayWithPEASnippet2"); + } + + public static boolean testDoubleArrayWithPEASnippet0() { + return Arrays.equals(new double[]{0.0d}, new double[]{-0.0d}); + } + + public static boolean testDoubleArrayWithPEASnippet1() { + return Arrays.equals(new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}, new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}); + } + + public static boolean testDoubleArrayWithPEASnippet2() { + return Arrays.equals(new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}, new double[]{Double.longBitsToDouble(0x7ff0000000000001L)}); + } + + @Test + public void testDoubleArrayWithPEA() { + test("testDoubleArrayWithPEASnippet0"); + test("testDoubleArrayWithPEASnippet1"); + test("testDoubleArrayWithPEASnippet2"); + } + + public static final float[] FLOAT_ARRAY1 = new float[]{0.0f}; + public static final float[] FLOAT_ARRAY2 = new float[]{-0.0f}; + public static final float[] FLOAT_ARRAY3 = new float[]{Float.intBitsToFloat(0x7fc00000)}; + public static final float[] FLOAT_ARRAY4 = new float[]{Float.intBitsToFloat(0x7f800001)}; + + public static final double[] DOUBLE_ARRAY1 = new double[]{0.0d}; + public static final double[] DOUBLE_ARRAY2 = new double[]{-0.0d}; + public static final double[] DOUBLE_ARRAY3 = new double[]{Double.longBitsToDouble(0x7ff8000000000000L)}; + public static final double[] DOUBLE_ARRAY4 = new double[]{Double.longBitsToDouble(0x7ff0000000000001L)}; + + public static boolean testStableFloatArraySnippet0() { + return Arrays.equals(FLOAT_ARRAY1, FLOAT_ARRAY2); + } + + public static boolean testStableFloatArraySnippet1() { + return Arrays.equals(FLOAT_ARRAY1, FLOAT_ARRAY2); + } + + public static boolean testStableDoubleArraySnippet0() { + return Arrays.equals(DOUBLE_ARRAY1, DOUBLE_ARRAY2); + } + + public static boolean testStableDoubleArraySnippet1() { + return Arrays.equals(DOUBLE_ARRAY3, DOUBLE_ARRAY4); + } + + public void testStableArray(String methodName) { + ResolvedJavaMethod method = getResolvedJavaMethod(methodName); + Result expected = executeExpected(method, null); + + StructuredGraph graph = parseEager(method, AllowAssumptions.YES); + + for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) { + if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) { + ConstantNode newConstantNode = ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess()); + newConstantNode = graph.unique(newConstantNode); + constantNode.replaceAndDelete(newConstantNode); + } + } + + CompilationResult result = compile(method, graph); + InstalledCode code = addMethod(graph.getDebug(), method, result); + + Result actual; + + try { + actual = new Result(code.executeVarargs(), null); + } catch (Exception e) { + actual = new Result(null, e); + } + + assertEquals(expected, actual); + } + + @Test + public void testStableArray() { + testStableArray("testStableFloatArraySnippet0"); + testStableArray("testStableFloatArraySnippet1"); + testStableArray("testStableDoubleArraySnippet0"); + testStableArray("testStableDoubleArraySnippet1"); + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeBooleanAccessTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/UnsafeBooleanAccessTest.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,81 @@ +/* + * 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. + */ +package org.graalvm.compiler.replacements.test; + +import java.lang.reflect.Field; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; + +public class UnsafeBooleanAccessTest extends GraalCompilerTest { + + private static short onHeapMemory; + + private static final Object onHeapMemoryBase; + private static final long onHeapMemoryOffset; + + static { + try { + Field staticField = UnsafeBooleanAccessTest.class.getDeclaredField("onHeapMemory"); + onHeapMemoryBase = UNSAFE.staticFieldBase(staticField); + onHeapMemoryOffset = UNSAFE.staticFieldOffset(staticField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static boolean testGetBooleanSnippet() { + UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204); + return UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset); + } + + @Test + public void testGetBoolean() { + test("testGetBooleanSnippet"); + } + + public static short testPutBooleanSnippet() { + UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204); + boolean bool = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset); + UNSAFE.putBoolean(onHeapMemoryBase, onHeapMemoryOffset, bool); + return onHeapMemory; + } + + @Test + public void testPutBoolean() { + test("testPutBooleanSnippet"); + } + + public static boolean testAndBooleanSnippet() { + UNSAFE.putShort(onHeapMemoryBase, onHeapMemoryOffset, (short) 0x0204); + boolean bool0 = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset); + boolean bool1 = UNSAFE.getBoolean(onHeapMemoryBase, onHeapMemoryOffset + 1); + return bool0 & bool1; + } + + @Test + public void testAndBoolean() { + test("testAndBooleanSnippet"); + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Tue Sep 05 10:09:44 2017 -0700 @@ -59,8 +59,10 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.IntegerConvertNode; +import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.LeftShiftNode; import org.graalvm.compiler.nodes.calc.NarrowNode; @@ -577,7 +579,7 @@ } else { memoryRead.setGuard(guard); } - ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible); + ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, compressible), readKind); load.replaceAtUsages(readValue); return memoryRead; } @@ -592,11 +594,20 @@ // An unsafe read must not float otherwise it may float above // a test guaranteeing the read is safe. memoryRead.setForceFixed(true); - ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, false); + ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, false), readKind); load.replaceAtUsages(readValue); graph.replaceFixedWithFixed(load, memoryRead); } + private static ValueNode performBooleanCoercionIfNecessary(ValueNode readValue, JavaKind readKind) { + if (readKind == JavaKind.Boolean) { + StructuredGraph graph = readValue.graph(); + IntegerEqualsNode eq = graph.addOrUnique(new IntegerEqualsNode(readValue, ConstantNode.forInt(0, graph))); + return graph.addOrUnique(new ConditionalNode(eq, ConstantNode.forBoolean(false, graph), ConstantNode.forBoolean(true, graph))); + } + return readValue; + } + protected void lowerUnsafeStoreNode(RawStoreNode store) { StructuredGraph graph = store.graph(); boolean compressible = store.value().getStackKind() == JavaKind.Object; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Tue Sep 05 10:09:44 2017 -0700 @@ -189,9 +189,7 @@ r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class); r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class); r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class); - r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class); r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class); - r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class); } private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java Tue Sep 05 10:09:44 2017 -0700 @@ -95,11 +95,16 @@ return length; } + private static boolean isNaNFloat(JavaConstant constant) { + JavaKind kind = constant.getJavaKind(); + return (kind == JavaKind.Float && Float.isNaN(constant.asFloat())) || (kind == JavaKind.Double && Double.isNaN(constant.asDouble())); + } + private static boolean arrayEquals(ConstantReflectionProvider constantReflection, JavaConstant a, JavaConstant b, int len) { for (int i = 0; i < len; i++) { JavaConstant aElem = constantReflection.readArrayElement(a, i); JavaConstant bElem = constantReflection.readArrayElement(b, i); - if (!constantReflection.constantEquals(aElem, bElem)) { + if (!constantReflection.constantEquals(aElem, bElem) && !(isNaNFloat(aElem) && isNaNFloat(bElem))) { return false; } } @@ -145,8 +150,28 @@ ValueNode entry1 = tool.getEntry(virtual1, i); ValueNode entry2 = tool.getEntry(virtual2, i); if (entry1 != entry2) { - // the contents might be different - allEqual = false; + if (entry1 instanceof ConstantNode && entry2 instanceof ConstantNode) { + // Float NaN constants are different constant nodes but treated as + // equal in Arrays.equals([F[F) or Arrays.equals([D[D). + if (entry1.getStackKind() == JavaKind.Float && entry2.getStackKind() == JavaKind.Float) { + float value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asFloat(); + float value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asFloat(); + if (Float.floatToIntBits(value1) != Float.floatToIntBits(value2)) { + allEqual = false; + } + } else if (entry1.getStackKind() == JavaKind.Double && entry2.getStackKind() == JavaKind.Double) { + double value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asDouble(); + double value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asDouble(); + if (Double.doubleToLongBits(value1) != Double.doubleToLongBits(value2)) { + allEqual = false; + } + } else { + allEqual = false; + } + } else { + // the contents might be different + allEqual = false; + } } if (entry1.stamp().alwaysDistinct(entry2.stamp())) { // the contents are different diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ExplodeLoopNode.java Tue Sep 05 10:09:44 2017 -0700 @@ -57,7 +57,7 @@ for (Node n : currentNext.cfgSuccessors()) { succs.add(n); } - if (succs.size() == 1) { + if (succs.size() == 1 && succs.get(0) != currentNext) { currentNext = succs.get(0); } else { return null; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerMulHighNode.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,69 +25,28 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; -import java.util.function.BiFunction; - -import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.MulHigh; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.BinaryNode; -import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.Value; @NodeInfo(shortName = "*H", cycles = CYCLES_2, size = SIZE_2) -public final class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable { +public final class IntegerMulHighNode extends BinaryArithmeticNode implements Canonicalizable.BinaryCommutative { public static final NodeClass TYPE = NodeClass.create(IntegerMulHighNode.class); public IntegerMulHighNode(ValueNode x, ValueNode y) { - this((IntegerStamp) x.stamp().unrestricted(), x, y); - } - - public IntegerMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) { - super(TYPE, stamp, x, y); - } - - /** - * Determines the minimum and maximum result of this node for the given inputs and returns the - * result of the given BiFunction on the minimum and maximum values. - */ - private T processExtremes(Stamp forX, Stamp forY, BiFunction op) { - IntegerStamp xStamp = (IntegerStamp) forX; - IntegerStamp yStamp = (IntegerStamp) forY; - - JavaKind kind = getStackKind(); - assert kind == JavaKind.Int || kind == JavaKind.Long; - long[] xExtremes = {xStamp.lowerBound(), xStamp.upperBound()}; - long[] yExtremes = {yStamp.lowerBound(), yStamp.upperBound()}; - long min = Long.MAX_VALUE; - long max = Long.MIN_VALUE; - for (long a : xExtremes) { - for (long b : yExtremes) { - long result = kind == JavaKind.Int ? multiplyHigh((int) a, (int) b) : multiplyHigh(a, b); - min = Math.min(min, result); - max = Math.max(max, result); - } - } - return op.apply(min, max); - } - - @Override - public Stamp foldStamp(Stamp stampX, Stamp stampY) { - return processExtremes(stampX, stampY, (min, max) -> StampFactory.forInteger(getStackKind(), min, max)); - } - - @SuppressWarnings("cast") - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this); + super(TYPE, ArithmeticOpTable::getMulHigh, x, y); } @Override @@ -97,29 +56,35 @@ nodeValueMap.setResult(this, gen.emitMulHigh(a, b)); } - public static int multiplyHigh(int x, int y) { - long r = (long) x * (long) y; - return (int) (r >> 32); + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + ValueNode ret = super.canonical(tool, forX, forY); + if (ret != this) { + return ret; + } + + if (forX.isConstant() && !forY.isConstant()) { + // we try to swap and canonicalize + ValueNode improvement = canonical(tool, forY, forX); + if (improvement != this) { + return improvement; + } + // if this fails we only swap + return new IntegerMulHighNode(forY, forX); + } + return canonical(this, forY); } - public static long multiplyHigh(long x, long y) { - // Checkstyle: stop - long x0, y0, z0; - long x1, y1, z1, z2, t; - // Checkstyle: resume - - x0 = x & 0xFFFFFFFFL; - x1 = x >> 32; - - y0 = y & 0xFFFFFFFFL; - y1 = y >> 32; - - z0 = x0 * y0; - t = x1 * y0 + (z0 >>> 32); - z1 = t & 0xFFFFFFFFL; - z2 = t >> 32; - z1 += x0 * y1; - - return x1 * y1 + z2 + (z1 >> 32); + private static ValueNode canonical(IntegerMulHighNode self, ValueNode forY) { + if (forY.isConstant()) { + Constant c = forY.asConstant(); + if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { + long i = ((PrimitiveConstant) c).asLong(); + if (i == 0 || i == 1) { + return ConstantNode.forIntegerStamp(self.stamp(), 0); + } + } + } + return self; } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/UnsignedMulHighNode.java Tue Sep 05 10:09:44 2017 -0700 @@ -25,86 +25,28 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; -import java.util.function.BiFunction; - -import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.UMulHigh; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.BinaryNode; -import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.Value; @NodeInfo(shortName = "|*H|", cycles = CYCLES_2, size = SIZE_2) -public final class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable { - +public final class UnsignedMulHighNode extends BinaryArithmeticNode implements Canonicalizable.BinaryCommutative { public static final NodeClass TYPE = NodeClass.create(UnsignedMulHighNode.class); public UnsignedMulHighNode(ValueNode x, ValueNode y) { - this((IntegerStamp) x.stamp().unrestricted(), x, y); - } - - public UnsignedMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) { - super(TYPE, stamp, x, y); - } - - private static long[] getUnsignedExtremes(IntegerStamp stamp) { - if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) { - /* - * If -1 and 0 are both in the signed range, then we can't say anything about the - * unsigned range, so we have to return [0, MAX_UNSIGNED]. - */ - return new long[]{0, -1L}; - } else { - return new long[]{stamp.lowerBound(), stamp.upperBound()}; - } - } - - /** - * Determines the minimum and maximum result of this node for the given inputs and returns the - * result of the given BiFunction on the minimum and maximum values. Note that the minima and - * maxima are calculated using signed min/max functions, while the values themselves are - * unsigned. - */ - private T processExtremes(Stamp forX, Stamp forY, BiFunction op) { - IntegerStamp xStamp = (IntegerStamp) forX; - IntegerStamp yStamp = (IntegerStamp) forY; - - JavaKind kind = getStackKind(); - assert kind == JavaKind.Int || kind == JavaKind.Long; - long[] xExtremes = getUnsignedExtremes(xStamp); - long[] yExtremes = getUnsignedExtremes(yStamp); - long min = Long.MAX_VALUE; - long max = Long.MIN_VALUE; - for (long a : xExtremes) { - for (long b : yExtremes) { - long result = kind == JavaKind.Int ? multiplyHighUnsigned((int) a, (int) b) : multiplyHighUnsigned(a, b); - min = Math.min(min, result); - max = Math.max(max, result); - } - } - return op.apply(min, max); - } - - @SuppressWarnings("cast") - @Override - public Stamp foldStamp(Stamp stampX, Stamp stampY) { - // if min is negative, then the value can reach into the unsigned range - return processExtremes(stampX, stampY, (min, max) -> (min == (long) max || min >= 0) ? StampFactory.forInteger(getStackKind(), min, max) : StampFactory.forKind(getStackKind())); - } - - @SuppressWarnings("cast") - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - return processExtremes(forX.stamp(), forY.stamp(), (min, max) -> min == (long) max ? ConstantNode.forIntegerKind(getStackKind(), min) : this); + super(TYPE, ArithmeticOpTable::getUMulHigh, x, y); } @Override @@ -114,31 +56,35 @@ nodeValueMap.setResult(this, gen.emitUMulHigh(a, b)); } - public static int multiplyHighUnsigned(int x, int y) { - long xl = x & 0xFFFFFFFFL; - long yl = y & 0xFFFFFFFFL; - long r = xl * yl; - return (int) (r >> 32); + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + ValueNode ret = super.canonical(tool, forX, forY); + if (ret != this) { + return ret; + } + + if (forX.isConstant() && !forY.isConstant()) { + // we try to swap and canonicalize + ValueNode improvement = canonical(tool, forY, forX); + if (improvement != this) { + return improvement; + } + // if this fails we only swap + return new UnsignedMulHighNode(forY, forX); + } + return canonical(this, forY); } - public static long multiplyHighUnsigned(long x, long y) { - // Checkstyle: stop - long x0, y0, z0; - long x1, y1, z1, z2, t; - // Checkstyle: resume - - x0 = x & 0xFFFFFFFFL; - x1 = x >>> 32; - - y0 = y & 0xFFFFFFFFL; - y1 = y >>> 32; - - z0 = x0 * y0; - t = x1 * y0 + (z0 >>> 32); - z1 = t & 0xFFFFFFFFL; - z2 = t >>> 32; - z1 += x0 * y1; - - return x1 * y1 + z2 + (z1 >>> 32); + private static ValueNode canonical(UnsignedMulHighNode self, ValueNode forY) { + if (forY.isConstant()) { + Constant c = forY.asConstant(); + if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { + long i = ((PrimitiveConstant) c).asLong(); + if (i == 0 || i == 1) { + return ConstantNode.forIntegerStamp(self.stamp(), 0); + } + } + } + return self; } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/TestJMHBlackbox.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/TestJMHBlackbox.java Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,43 @@ +/* + * 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. + */ +package micro.benchmarks; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Warmup; + +@Warmup(iterations = 1) +@Measurement(iterations = 1) +@Fork(1) +/** + * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly. + */ +public class TestJMHBlackbox { + + @Benchmark + public void testJMH() { + // This method was intentionally left blank. + } + +} diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -952,7 +952,7 @@ if (now <= prev) { return prev; // same or retrograde time; } - const uint64_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&Bsd::_max_abstime, prev); + const uint64_t obsv = Atomic::cmpxchg(now, &Bsd::_max_abstime, prev); assert(obsv >= prev, "invariant"); // Monotonicity // If the CAS succeeded then we're done and return "now". // If the CAS failed and the observed value "obsv" is >= now then diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1747,9 +1747,11 @@ {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, #if defined(VM_LITTLE_ENDIAN) - {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"}, + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64 LE"}, + {EM_SH, EM_SH, ELFCLASS32, ELFDATA2LSB, (char*)"SuperH"}, #else - {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64 LE"}, + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, + {EM_SH, EM_SH, ELFCLASS32, ELFDATA2MSB, (char*)"SuperH BE"}, #endif {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, @@ -1791,9 +1793,11 @@ static Elf32_Half running_arch_code=EM_MIPS; #elif (defined M68K) static Elf32_Half running_arch_code=EM_68K; +#elif (defined SH) + static Elf32_Half running_arch_code=EM_SH; #else #error Method os::dll_load requires that one of following is defined:\ - AARCH64, ALPHA, ARM, AMD64, IA32, IA64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, S390, __sparc + AARCH64, ALPHA, ARM, AMD64, IA32, IA64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, S390, SH, __sparc #endif // Identify compatability class for VM's architecture and library's architecture diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1197,7 +1197,7 @@ if (now <= prev) { return prev; // same or retrograde time; } - const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); + const hrtime_t obsv = Atomic::cmpxchg(now, &max_hrtime, prev); assert(obsv >= prev, "invariant"); // Monotonicity // If the CAS succeeded then we're done and return "now". // If the CAS failed and the observed value "obsv" is >= now then diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp --- a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -30,6 +30,8 @@ #error "Atomic currently only impleneted for PPC64" #endif +#include "utilities/debug.hpp" + // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -93,9 +95,21 @@ #define strasm_nobarrier "" #define strasm_nobarrier_clobber_memory "" -inline jint Atomic::add (jint add_value, volatile jint* dest) { +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; - unsigned int result; +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + + D result; __asm__ __volatile__ ( strasm_lwsync @@ -108,13 +122,17 @@ : /*%1*/"r" (add_value), /*%2*/"r" (dest) : "cc", "memory" ); - return (jint) result; + return result; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); - long result; + D result; __asm__ __volatile__ ( strasm_lwsync @@ -127,11 +145,7 @@ : /*%1*/"r" (add_value), /*%2*/"r" (dest) : "cc", "memory" ); - return (intptr_t) result; -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); + return result; } @@ -306,8 +320,13 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not @@ -368,16 +387,22 @@ cmpxchg_post_membar(order); - return (jbyte)(unsigned char)old_value; + return PrimitiveConversions::cast((unsigned char)old_value); } -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -412,16 +437,22 @@ cmpxchg_post_membar(order); - return (jint) old_value; + return old_value; } -inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - long old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -456,15 +487,7 @@ cmpxchg_post_membar(order); - return (jlong) old_value; -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); + return old_value; } #undef strasm_sync diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp --- a/hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -25,8 +25,6 @@ #ifndef OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP #define OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -42,13 +40,25 @@ inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } -inline jint Atomic::add (jint add_value, volatile jint* dest) { - jint addend = add_value; +template +struct Atomic::PlatformAdd + : Atomic::FetchAndAdd > +{ + template + D fetch_and_add(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::fetch_and_add(I add_value, D volatile* dest) const { + STATIC_ASSERT(4 == sizeof(I)); + STATIC_ASSERT(4 == sizeof(D)); + D old_value; __asm__ volatile ( "lock xaddl %0,(%2)" - : "=r" (addend) - : "0" (addend), "r" (dest) + : "=r" (old_value) + : "0" (add_value), "r" (dest) : "cc", "memory"); - return addend + add_value; + return old_value; } inline void Atomic::inc (volatile jint* dest) { @@ -81,8 +91,13 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(1 == sizeof(T)); __asm__ volatile ( "lock cmpxchgb %1,(%3)" : "=a" (exchange_value) : "q" (exchange_value), "a" (compare_value), "r" (dest) @@ -90,7 +105,13 @@ return exchange_value; } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ( "lock cmpxchgl %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -102,17 +123,17 @@ inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - intptr_t addend = add_value; +template<> +template +inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) const { + STATIC_ASSERT(8 == sizeof(I)); + STATIC_ASSERT(8 == sizeof(D)); + D old_value; __asm__ __volatile__ ( "lock xaddq %0,(%2)" - : "=r" (addend) - : "0" (addend), "r" (dest) + : "=r" (old_value) + : "0" (add_value), "r" (dest) : "cc", "memory"); - return addend + add_value; -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); + return old_value; } inline void Atomic::inc_ptr(volatile intptr_t* dest) { @@ -137,7 +158,13 @@ return exchange_value; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ( "lock cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -145,27 +172,10 @@ return exchange_value; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #else // !AMD64 -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)Atomic::add((jint)add_value, (volatile jint*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)Atomic::add((jint)add_value, (volatile jint*)dest); -} - - inline void Atomic::inc_ptr(volatile intptr_t* dest) { inc((volatile jint*)dest); } @@ -184,16 +194,14 @@ void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value, os::is_MP()); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } inline jlong Atomic::load(const volatile jlong* src) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -908,6 +908,12 @@ // workaround for OS X 10.9.0 (Mavericks) // pthread_get_stacksize_np returns 128 pages even though the actual size is 2048 pages if (pthread_main_np() == 1) { + // At least on Mac OS 10.12 we have observed stack sizes not aligned + // to pages boundaries. This can be provoked by e.g. setrlimit() (ulimit -s xxxx in the + // shell). Apparently Mac OS actually rounds upwards to next multiple of page size, + // however, we round downwards here to be on the safe side. + *size = align_down(*size, getpagesize()); + if ((*size) < (DEFAULT_MAIN_THREAD_STACK_PAGES * (size_t)getpagesize())) { char kern_osrelease[256]; size_t kern_osrelease_size = sizeof(kern_osrelease); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp --- a/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -57,9 +57,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int m68k_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int m68k_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -74,7 +74,7 @@ } /* Atomically add an int to memory. */ -static inline int m68k_add_and_fetch(volatile int *ptr, int add_value) { +static inline int m68k_add_and_fetch(int add_value, volatile int *ptr) { for (;;) { // Loop until success. @@ -118,9 +118,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int arm_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int arm_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -135,7 +135,7 @@ } /* Atomically add an int to memory. */ -static inline int arm_add_and_fetch(volatile int *ptr, int add_value) { +static inline int arm_add_and_fetch(int add_value, volatile int *ptr) { for (;;) { // Loop until a __kernel_cmpxchg succeeds. @@ -173,32 +173,38 @@ *dest = store_value; } -inline jint Atomic::add(jint add_value, volatile jint* dest) { +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + #ifdef ARM - return arm_add_and_fetch(dest, add_value); + return add_using_helper(arm_add_and_fetch, add_value, dest); #else #ifdef M68K - return m68k_add_and_fetch(dest, add_value); + return add_using_helper(m68k_add_and_fetch, add_value, dest); #else return __sync_add_and_fetch(dest, add_value); #endif // M68K #endif // ARM } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { -#ifdef ARM - return arm_add_and_fetch(dest, add_value); -#else -#ifdef M68K - return m68k_add_and_fetch(dest, add_value); -#else +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); + return __sync_add_and_fetch(dest, add_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void *) add_ptr(add_value, (volatile intptr_t *) dest); } inline void Atomic::inc(volatile jint* dest) { @@ -267,55 +273,38 @@ (volatile intptr_t*) dest); } -inline jint Atomic::cmpxchg(jint exchange_value, - volatile jint* dest, - jint compare_value, - cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_CAST(4 == sizeof(T)); #ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(arm_compare_and_swap, exchange_value, dest, compare_value); #else #ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(m68k_compare_and_swap, exchange_value, dest, compare_value); #else return __sync_val_compare_and_swap(dest, compare_value, exchange_value); #endif // M68K #endif // ARM } -inline jlong Atomic::cmpxchg(jlong exchange_value, - volatile jlong* dest, - jlong compare_value, - cmpxchg_memory_order order) { - +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_CAST(8 == sizeof(T)); return __sync_val_compare_and_swap(dest, compare_value, exchange_value); } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest, - intptr_t compare_value, - cmpxchg_memory_order order) { -#ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); -#else -#ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); -#else - return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, - volatile void* dest, - void* compare_value, - cmpxchg_memory_order order) { - - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); -} - inline jlong Atomic::load(const volatile jlong* src) { volatile jlong dest; os::atomic_copy64(src, &dest); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp --- a/hotspot/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_aarch64/vm/atomic_linux_aarch64.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -47,10 +47,15 @@ inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } -inline jint Atomic::add(jint add_value, volatile jint* dest) +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > { - return __sync_add_and_fetch(dest, add_value); -} + template + D add_and_fetch(I add_value, D volatile* dest) const { + return __sync_add_and_fetch(dest, add_value); + } +}; inline void Atomic::inc(volatile jint* dest) { @@ -85,9 +90,13 @@ (volatile intptr_t*) dest); } -template T generic_cmpxchg(T exchange_value, volatile T* dest, - T compare_value, cmpxchg_memory_order order) -{ +template +template +inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(byte_size == sizeof(T)); if (order == memory_order_relaxed) { T value = compare_value; __atomic_compare_exchange(dest, &value, &exchange_value, /*weak*/false, @@ -98,30 +107,9 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) -{ - return __sync_add_and_fetch(dest, add_value); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) -{ - return (void *) add_ptr(add_value, (volatile intptr_t *) dest); -} - inline void Atomic::inc_ptr(volatile intptr_t* dest) { add_ptr(1, dest); @@ -139,24 +127,6 @@ return res; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) -{ - return generic_cmpxchg(exchange_value, dest, compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) -{ - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp --- a/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_arm/vm/atomic_linux_arm.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -91,9 +91,21 @@ // // For ARMv7 we add explicit barriers in the stubs. -inline jint Atomic::add(jint add_value, volatile jint* dest) { +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_ASSERT(4 == sizeof(I)); + STATIC_ASSERT(4 == sizeof(D)); #ifdef AARCH64 - jint val; + D val; int tmp; __asm__ volatile( "1:\n\t" @@ -106,7 +118,7 @@ : "memory"); return val; #else - return (*os::atomic_add_func)(add_value, dest); + return add_using_helper(os::atomic_add_func, add_value, dest); #endif } @@ -118,9 +130,13 @@ Atomic::add(-1, (volatile jint *)dest); } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { #ifdef AARCH64 - intptr_t val; +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_ASSERT(8 == sizeof(I)); + STATIC_ASSERT(8 == sizeof(D)); + D val; int tmp; __asm__ volatile( "1:\n\t" @@ -132,14 +148,8 @@ : [add_val] "r" (add_value), [dest] "r" (dest) : "memory"); return val; -#else - return (intptr_t)Atomic::add((jint)add_value, (volatile jint*)dest); -#endif } - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); -} +#endif // AARCH64 inline void Atomic::inc_ptr(volatile intptr_t* dest) { Atomic::add_ptr(1, dest); @@ -200,9 +210,38 @@ // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +#ifndef AARCH64 + +inline jint reorder_cmpxchg_func(jint exchange_value, + jint volatile* dest, + jint compare_value) { + // Warning: Arguments are swapped to avoid moving them for kernel call + return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest); +} + +inline jlong reorder_cmpxchg_long_func(jlong exchange_value, + jlong volatile* dest, + jlong compare_value) { + assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!"); + // Warning: Arguments are swapped to avoid moving them for kernel call + return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest); +} + +#endif // !AARCH64 + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef AARCH64 - jint rv; + T rv; int tmp; __asm__ volatile( "1:\n\t" @@ -220,14 +259,19 @@ : "memory"); return rv; #else - // Warning: Arguments are swapped to avoid moving them for kernel call - return (*os::atomic_cmpxchg_func)(compare_value, exchange_value, dest); + return cmpxchg_using_helper(reorder_cmpxchg_func, exchange_value, dest, compare_value); #endif } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); #ifdef AARCH64 - jlong rv; + T rv; int tmp; __asm__ volatile( "1:\n\t" @@ -245,21 +289,8 @@ : "memory"); return rv; #else - assert(VM_Version::supports_cx8(), "Atomic compare and exchange jlong not supported on this architecture!"); - return (*os::atomic_cmpxchg_long_func)(compare_value, exchange_value, dest); + return cmpxchg_using_helper(reorder_cmpxchg_long_func, exchange_value, dest, compare_value); #endif } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { -#ifdef AARCH64 - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -#else - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -#endif -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); -} - #endif // OS_CPU_LINUX_ARM_VM_ATOMIC_LINUX_ARM_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp --- a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -93,9 +93,21 @@ #define strasm_nobarrier "" #define strasm_nobarrier_clobber_memory "" -inline jint Atomic::add (jint add_value, volatile jint* dest) { +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; - unsigned int result; +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + + D result; __asm__ __volatile__ ( strasm_lwsync @@ -108,13 +120,17 @@ : /*%1*/"r" (add_value), /*%2*/"r" (dest) : "cc", "memory" ); - return (jint) result; + return result; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); - long result; + D result; __asm__ __volatile__ ( strasm_lwsync @@ -127,11 +143,7 @@ : /*%1*/"r" (add_value), /*%2*/"r" (dest) : "cc", "memory" ); - return (intptr_t) result; -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); + return result; } @@ -306,8 +318,13 @@ } } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not @@ -368,16 +385,22 @@ cmpxchg_post_membar(order); - return (jbyte)(unsigned char)old_value; + return PrimitiveConversions::cast((unsigned char)old_value); } -inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - unsigned int old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -412,16 +435,22 @@ cmpxchg_post_membar(order); - return (jint) old_value; + return old_value; } -inline jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); // Note that cmpxchg guarantees a two-way memory barrier across // the cmpxchg, so it's really a a 'fence_cmpxchg_fence' if not // specified otherwise (see atomic.hpp). - long old_value; + T old_value; const uint64_t zero = 0; cmpxchg_pre_membar(order); @@ -456,15 +485,7 @@ cmpxchg_post_membar(order); - return (jlong) old_value; -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); + return old_value; } #undef strasm_sync diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp --- a/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -82,8 +82,21 @@ // The return value of the method is the value that was successfully stored. At the // time the caller receives back control, the value in memory may have changed already. -inline jint Atomic::add(jint inc, volatile jint*dest) { - unsigned int old, upd; +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + + D old, upd; if (VM_Version::has_LoadAndALUAtomicV1()) { __asm__ __volatile__ ( @@ -105,7 +118,7 @@ //---< inputs >--- : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r0", "r2", "r3" + : "cc", "r0", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -120,16 +133,21 @@ //---< inputs >--- : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc" + : "cc", "memory" ); } - return (jint)upd; + return upd; } -inline intptr_t Atomic::add_ptr(intptr_t inc, volatile intptr_t* dest) { - unsigned long old, upd; +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); + + D old, upd; if (VM_Version::has_LoadAndALUAtomicV1()) { __asm__ __volatile__ ( @@ -151,7 +169,7 @@ //---< inputs >--- : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r0", "r2", "r3" + : "cc", "r0", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -166,15 +184,11 @@ //---< inputs >--- : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc" + : "cc", "memory" ); } - return (intptr_t)upd; -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); + return upd; } @@ -214,7 +228,7 @@ : // : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r2", "r3" + : "cc", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -229,7 +243,7 @@ //---< inputs >--- : //---< clobbered >--- - : "cc" + : "cc", "memory" ); } } @@ -258,7 +272,7 @@ : // : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r2", "r3" + : "cc", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -273,7 +287,7 @@ //---< inputs >--- : //---< clobbered >--- - : "cc" + : "cc", "memory" ); } } @@ -317,7 +331,7 @@ : // : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r2", "r3" + : "cc", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -335,7 +349,7 @@ //---< inputs >--- : //---< clobbered >--- - : "cc" + : "cc", "memory" ); } } @@ -364,7 +378,7 @@ : // : [inc] "a" (inc) // read-only. //---< clobbered >--- - : "cc", "r2", "r3" + : "cc", "r2", "r3", "memory" ); } else { __asm__ __volatile__ ( @@ -382,7 +396,7 @@ //---< inputs >--- : //---< clobbered >--- - : "cc" + : "cc", "memory" ); } } @@ -420,7 +434,7 @@ //---< inputs >--- : [upd] "d" (xchg_val) // read-only, value to be written to memory //---< clobbered >--- - : "cc" + : "cc", "memory" ); return (jint)old; @@ -439,7 +453,7 @@ //---< inputs >--- : [upd] "d" (xchg_val) // read-only, value to be written to memory //---< clobbered >--- - : "cc" + : "cc", "memory" ); return (intptr_t)old; @@ -478,8 +492,18 @@ // function is performed before the operand is fetched and again after the // operation is completed." -jint Atomic::cmpxchg(jint xchg_val, volatile jint* dest, jint cmp_val, cmpxchg_memory_order unused) { - unsigned long old; +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T xchg_val, + T volatile* dest, + T cmp_val, + cmpxchg_memory_order unused) const { + STATIC_ASSERT(4 == sizeof(T)); + T old; __asm__ __volatile__ ( " CS %[old],%[upd],%[mem] \n\t" // Try to xchg upd with mem. @@ -490,14 +514,20 @@ : [upd] "d" (xchg_val) , "0" (cmp_val) // Read-only, initial value for [old] (operand #0). // clobbered - : "cc" + : "cc", "memory" ); - return (jint)old; + return old; } -jlong Atomic::cmpxchg(jlong xchg_val, volatile jlong* dest, jlong cmp_val, cmpxchg_memory_order unused) { - unsigned long old; +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T xchg_val, + T volatile* dest, + T cmp_val, + cmpxchg_memory_order unused) const { + STATIC_ASSERT(8 == sizeof(T)); + T old; __asm__ __volatile__ ( " CSG %[old],%[upd],%[mem] \n\t" // Try to xchg upd with mem. @@ -508,18 +538,10 @@ : [upd] "d" (xchg_val) , "0" (cmp_val) // Read-only, initial value for [old] (operand #0). // clobbered - : "cc" + : "cc", "memory" ); - return (jlong)old; -} - -void* Atomic::cmpxchg_ptr(void *xchg_val, volatile void* dest, void* cmp_val, cmpxchg_memory_order unused) { - return (void*)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused); -} - -intptr_t Atomic::cmpxchg_ptr(intptr_t xchg_val, volatile intptr_t* dest, intptr_t cmp_val, cmpxchg_memory_order unused) { - return (intptr_t)cmpxchg((jlong)xchg_val, (volatile jlong*)dest, (jlong)cmp_val, unused); + return old; } inline jlong Atomic::load(const volatile jlong* src) { return *src; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp --- a/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -51,8 +51,21 @@ inline jlong Atomic::load(const volatile jlong* src) { return *src; } -inline jint Atomic::add (jint add_value, volatile jint* dest) { - intptr_t rv; +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + + D rv; __asm__ volatile( "1: \n\t" " ld [%2], %%o2\n\t" @@ -68,8 +81,12 @@ return rv; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - intptr_t rv; +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); + + D rv; __asm__ volatile( "1: \n\t" " ldx [%2], %%o2\n\t" @@ -85,10 +102,6 @@ return rv; } -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr((intptr_t)add_value, (volatile intptr_t*)dest); -} - inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { intptr_t rv = exchange_value; @@ -121,9 +134,18 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - jint rv; +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + T rv; __asm__ volatile( " cas [%2], %3, %0" : "=r" (rv) @@ -132,8 +154,14 @@ return rv; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - jlong rv; +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + T rv; __asm__ volatile( " casx [%2], %3, %0" : "=r" (rv) @@ -142,18 +170,4 @@ return rv; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - intptr_t rv; - __asm__ volatile( - " casx [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); -} - #endif // OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp --- a/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -25,8 +25,6 @@ #ifndef OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP #define OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -42,13 +40,25 @@ inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } -inline jint Atomic::add (jint add_value, volatile jint* dest) { - jint addend = add_value; +template +struct Atomic::PlatformAdd + : Atomic::FetchAndAdd > +{ + template + D fetch_and_add(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::fetch_and_add(I add_value, D volatile* dest) const { + STATIC_ASSERT(4 == sizeof(I)); + STATIC_ASSERT(4 == sizeof(D)); + D old_value; __asm__ volatile ( "lock xaddl %0,(%2)" - : "=r" (addend) - : "0" (addend), "r" (dest) + : "=r" (old_value) + : "0" (add_value), "r" (dest) : "cc", "memory"); - return addend + add_value; + return old_value; } inline void Atomic::inc (volatile jint* dest) { @@ -81,8 +91,13 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(1 == sizeof(T)); __asm__ volatile ("lock cmpxchgb %1,(%3)" : "=a" (exchange_value) : "q" (exchange_value), "a" (compare_value), "r" (dest) @@ -90,7 +105,13 @@ return exchange_value; } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ("lock cmpxchgl %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -102,17 +123,17 @@ inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - intptr_t addend = add_value; +template<> +template +inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) const { + STATIC_ASSERT(8 == sizeof(I)); + STATIC_ASSERT(8 == sizeof(D)); + D old_value; __asm__ __volatile__ ("lock xaddq %0,(%2)" - : "=r" (addend) - : "0" (addend), "r" (dest) + : "=r" (old_value) + : "0" (add_value), "r" (dest) : "cc", "memory"); - return addend + add_value; -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr(add_value, (volatile intptr_t*)dest); + return old_value; } inline void Atomic::inc_ptr(volatile intptr_t* dest) { @@ -137,7 +158,13 @@ return exchange_value; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order /* order */) const { + STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ("lock cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) @@ -145,27 +172,10 @@ return exchange_value; } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } #else // !AMD64 -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)Atomic::add((jint)add_value, (volatile jint*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)Atomic::add((jint)add_value, (volatile jint*)dest); -} - - inline void Atomic::inc_ptr(volatile intptr_t* dest) { inc((volatile jint*)dest); } @@ -184,16 +194,14 @@ void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value); } inline jlong Atomic::load(const volatile jlong* src) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp --- a/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -57,9 +57,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int m68k_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int m68k_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -74,7 +74,7 @@ } /* Atomically add an int to memory. */ -static inline int m68k_add_and_fetch(volatile int *ptr, int add_value) { +static inline int m68k_add_and_fetch(int add_value, volatile int *ptr) { for (;;) { // Loop until success. @@ -118,9 +118,9 @@ /* Perform an atomic compare and swap: if the current value of `*PTR' is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of `*PTR' before the operation.*/ -static inline int arm_compare_and_swap(volatile int *ptr, - int oldval, - int newval) { +static inline int arm_compare_and_swap(int newval, + volatile int *ptr, + int oldval) { for (;;) { int prev = *ptr; if (prev != oldval) @@ -135,7 +135,7 @@ } /* Atomically add an int to memory. */ -static inline int arm_add_and_fetch(volatile int *ptr, int add_value) { +static inline int arm_add_and_fetch(int add_value, volatile int *ptr) { for (;;) { // Loop until a __kernel_cmpxchg succeeds. @@ -167,32 +167,38 @@ *dest = store_value; } -inline jint Atomic::add(jint add_value, volatile jint* dest) { +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(4 == sizeof(I)); + STATIC_CAST(4 == sizeof(D)); + #ifdef ARM - return arm_add_and_fetch(dest, add_value); + return add_using_helper(arm_add_and_fetch, add_value, dest); #else #ifdef M68K - return m68k_add_and_fetch(dest, add_value); + return add_using_helper(m68k_add_and_fetch, add_value, dest); #else return __sync_add_and_fetch(dest, add_value); #endif // M68K #endif // ARM } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { -#ifdef ARM - return arm_add_and_fetch(dest, add_value); -#else -#ifdef M68K - return m68k_add_and_fetch(dest, add_value); -#else +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_CAST(8 == sizeof(I)); + STATIC_CAST(8 == sizeof(D)); + return __sync_add_and_fetch(dest, add_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void *) add_ptr(add_value, (volatile intptr_t *) dest); } inline void Atomic::inc(volatile jint* dest) { @@ -261,55 +267,38 @@ (volatile intptr_t*) dest); } -inline jint Atomic::cmpxchg(jint exchange_value, - volatile jint* dest, - jint compare_value, - cmpxchg_memory_order order) { +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); #ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(arm_compare_and_swap, exchange_value, dest, compare_value); #else #ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); + return cmpxchg_using_helper(m68k_compare_and_swap, exchange_value, dest, compare_value); #else return __sync_val_compare_and_swap(dest, compare_value, exchange_value); #endif // M68K #endif // ARM } -inline jlong Atomic::cmpxchg(jlong exchange_value, - volatile jlong* dest, - jlong compare_value, - cmpxchg_memory_order order) { - +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); return __sync_val_compare_and_swap(dest, compare_value, exchange_value); } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - volatile intptr_t* dest, - intptr_t compare_value, - cmpxchg_memory_order order) { -#ifdef ARM - return arm_compare_and_swap(dest, compare_value, exchange_value); -#else -#ifdef M68K - return m68k_compare_and_swap(dest, compare_value, exchange_value); -#else - return __sync_val_compare_and_swap(dest, compare_value, exchange_value); -#endif // M68K -#endif // ARM -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, - volatile void* dest, - void* compare_value, - cmpxchg_memory_order order) { - - return (void *) cmpxchg_ptr((intptr_t) exchange_value, - (volatile intptr_t*) dest, - (intptr_t) compare_value, - order); -} - inline jlong Atomic::load(const volatile jlong* src) { volatile jlong dest; os::atomic_copy64(src, &dest); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -25,8 +25,6 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP #define OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP -#include "runtime/os.hpp" - // Implementation of class atomic inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } @@ -64,26 +62,21 @@ extern "C" jint _Atomic_swap32(jint exchange_value, volatile jint* dest); extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest); -extern "C" jint _Atomic_cas32(jint exchange_value, volatile jint* dest, jint compare_value); -extern "C" intptr_t _Atomic_cas64(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value); -extern "C" jlong _Atomic_casl (jlong exchange_value, volatile jlong* dest, jlong compare_value); - -extern "C" jint _Atomic_add32(jint inc, volatile jint* dest); -extern "C" intptr_t _Atomic_add64(intptr_t add_value, volatile intptr_t* dest); - - -inline jint Atomic::add (jint add_value, volatile jint* dest) { - return _Atomic_add32(add_value, dest); -} - -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return _Atomic_add64(add_value, dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add_ptr((intptr_t)add_value, (volatile intptr_t*)dest); -} - +// Implement ADD using a CAS loop. +template +struct Atomic::PlatformAdd VALUE_OBJ_CLASS_SPEC { + template + inline D operator()(I add_value, D volatile* dest) const { + D old_value = *dest; + while (true) { + D new_value = old_value + add_value; + D result = cmpxchg(new_value, dest, old_value); + if (result == old_value) break; + old_value = result; + } + return old_value + add_value; + } +}; inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { return _Atomic_swap32(exchange_value, dest); @@ -97,22 +90,40 @@ return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } +// No direct support for cmpxchg of bytes; emulate using int. +template<> +struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return _Atomic_cas32(exchange_value, dest, compare_value); +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + T rv; + __asm__ volatile( + " cas [%2], %3, %0" + : "=r" (rv) + : "0" (exchange_value), "r" (dest), "r" (compare_value) + : "memory"); + return rv; } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - // Return 64 bit value in %o0 - return _Atomic_cas64((intptr_t)exchange_value, (intptr_t *)dest, (intptr_t)compare_value); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return _Atomic_cas64(exchange_value, dest, compare_value); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value, order); +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + T rv; + __asm__ volatile( + " casx [%2], %3, %0" + : "=r" (rv) + : "0" (exchange_value), "r" (dest), "r" (compare_value) + : "memory"); + return rv; } #endif // OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il --- a/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/solaris_sparc.il Tue Sep 05 10:09:44 2017 -0700 @@ -73,74 +73,6 @@ .end - // Support for jint Atomic::cmpxchg(jint exchange_value, - // volatile jint* dest, - // jint compare_value) - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // compare_value: O2 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_cas32, 3 - .volatile - cas [%o1], %o2, %o0 - .nonvolatile - .end - - - // Support for intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, - // volatile intptr_t* dest, - // intptr_t compare_value) - // - // 64-bit - // - // Arguments: - // exchange_value: O0 - // dest: O1 - // compare_value: O2 - // - // Results: - // O0: the value previously stored in dest - - .inline _Atomic_cas64, 3 - .volatile - casx [%o1], %o2, %o0 - .nonvolatile - .end - - - // Support for jlong Atomic::cmpxchg(jlong exchange_value, - // volatile jlong* dest, - // jlong compare_value) - // - // 32-bit calling conventions - // - // Arguments: - // exchange_value: O1:O0 - // dest: O2 - // compare_value: O4:O3 - // - // Results: - // O1:O0: the value previously stored in dest - - .inline _Atomic_casl, 3 - .volatile - sllx %o0, 32, %o0 - srl %o1, 0, %o1 - or %o0,%o1,%o0 - sllx %o3, 32, %o3 - srl %o4, 0, %o4 - or %o3,%o4,%o3 - casx [%o2], %o3, %o0 - srl %o0, 0, %o1 - srlx %o0, 32, %o0 - .nonvolatile - .end - // Support for jlong Atomic::load and Atomic::store on v9. // // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst) @@ -158,58 +90,6 @@ .nonvolatile .end - // Support for jint Atomic::add(jint add_value, volatile jint* dest). - // - // Arguments: - // add_value: O0 (e.g., +1 or -1) - // dest: O1 - // - // Results: - // O0: the new value stored in dest - // - // Overwrites O3 - - .inline _Atomic_add32, 2 - .volatile - 2: - ld [%o1], %o2 - add %o0, %o2, %o3 - cas [%o1], %o2, %o3 - cmp %o2, %o3 - bne 2b - nop - add %o0, %o2, %o0 - .nonvolatile - .end - - - // Support for intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) - // - // 64-bit - // - // Arguments: - // add_value: O0 (e.g., +1 or -1) - // dest: O1 - // - // Results: - // O0: the new value stored in dest - // - // Overwrites O3 - - .inline _Atomic_add64, 2 - .volatile - 3: - ldx [%o1], %o2 - add %o0, %o2, %o3 - casx [%o1], %o2, %o3 - cmp %o2, %o3 - bne %xcc, 3b - nop - add %o0, %o2, %o0 - .nonvolatile - .end - - // Support for void Prefetch::read(void *loc, intx interval) // // Prefetch for several reads. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp --- a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -25,8 +25,6 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP #define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP -#include "runtime/os.hpp" - inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; } inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; } inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; } @@ -49,11 +47,12 @@ inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } -// For Sun Studio - implementation is in solaris_x86_[32/64].il. -// For gcc - implementation is just below. +// For Sun Studio - implementation is in solaris_x86_64.il. extern "C" { jint _Atomic_add(jint add_value, volatile jint* dest); + jlong _Atomic_add_long(jlong add_value, volatile jlong* dest); + jint _Atomic_xchg(jint exchange_value, volatile jint* dest); jbyte _Atomic_cmpxchg_byte(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value); @@ -63,42 +62,89 @@ jlong compare_value); } -inline jint Atomic::add (jint add_value, volatile jint* dest) { - return _Atomic_add(add_value, dest); +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + +// Not using add_using_helper; see comment for cmpxchg. +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_ASSERT(4 == sizeof(I)); + STATIC_ASSERT(4 == sizeof(D)); + return PrimitiveConversions::cast( + _Atomic_add(PrimitiveConversions::cast(add_value), + reinterpret_cast(dest))); +} + +// Not using add_using_helper; see comment for cmpxchg. +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_ASSERT(8 == sizeof(I)); + STATIC_ASSERT(8 == sizeof(D)); + return PrimitiveConversions::cast( + _Atomic_add_long(PrimitiveConversions::cast(add_value), + reinterpret_cast(dest))); } inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) { return _Atomic_xchg(exchange_value, dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_byte(exchange_value, dest, compare_value); -} +// Not using cmpxchg_using_helper here, because some configurations of +// Solaris compiler don't deal well with passing a "defined in .il" +// function as an argument. We *should* switch to using gcc-style +// inline assembly, but attempting to do so with Studio 12.4 ran into +// segfaults. -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg(exchange_value, dest, compare_value); -} - -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return _Atomic_cmpxchg_long(exchange_value, dest, compare_value); +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); + return PrimitiveConversions::cast( + _Atomic_cmpxchg_byte(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest), + PrimitiveConversions::cast(compare_value))); } +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + return PrimitiveConversions::cast( + _Atomic_cmpxchg(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest), + PrimitiveConversions::cast(compare_value))); +} -#ifdef AMD64 +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); + return PrimitiveConversions::cast( + _Atomic_cmpxchg_long(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest), + PrimitiveConversions::cast(compare_value))); +} + inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -extern "C" jlong _Atomic_add_long(jlong add_value, volatile jlong* dest); extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest); -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)_Atomic_add_long((jlong)add_value, (volatile jlong*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)_Atomic_add_long((jlong)add_value, (volatile jlong*)dest); -} - inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { return (intptr_t)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest); } @@ -107,59 +153,6 @@ return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest); } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value); -} - inline jlong Atomic::load(const volatile jlong* src) { return *src; } -#else // !AMD64 - -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)add((jint)add_value, (volatile jint*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add((jint)add_value, (volatile jint*)dest); -} - -inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) { - return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest); -} - -inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { - return (void*)xchg((jint)exchange_value, (volatile jint*)dest); -} - -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -extern "C" void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst); - -inline jlong Atomic::load(const volatile jlong* src) { - volatile jlong dest; - _Atomic_move_long(src, &dest); - return dest; -} - -inline void Atomic::store(jlong store_value, jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest); -} - -inline void Atomic::store(jlong store_value, volatile jlong* dest) { - _Atomic_move_long((volatile jlong*)&store_value, dest); -} - -#endif // AMD64 - - #endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp --- a/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -57,20 +57,28 @@ inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; } inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; } +template +struct Atomic::PlatformAdd + : Atomic::AddAndFetch > +{ + template + D add_and_fetch(I add_value, D volatile* dest) const; +}; + #ifdef AMD64 inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; } inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; } -inline jint Atomic::add (jint add_value, volatile jint* dest) { - return (jint)(*os::atomic_add_func)(add_value, dest); +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + return add_using_helper(os::atomic_add_func, add_value, dest); } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)(*os::atomic_add_ptr_func)(add_value, dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)(*os::atomic_add_ptr_func)(add_value, (volatile intptr_t*)dest); +template<> +template +inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const { + return add_using_helper(os::atomic_add_ptr_func, add_value, dest); } inline void Atomic::inc (volatile jint* dest) { @@ -109,32 +117,32 @@ return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest); } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_func)(exchange_value, dest, compare_value); -} - -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_byte_func)(exchange_value, dest, compare_value); -} +#define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \ + template<> \ + template \ + inline T Atomic::PlatformCmpxchg::operator()(T exchange_value, \ + T volatile* dest, \ + T compare_value, \ + cmpxchg_memory_order order) const { \ + STATIC_ASSERT(ByteSize == sizeof(T)); \ + return cmpxchg_using_helper(StubName, exchange_value, dest, compare_value); \ + } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { - return (*os::atomic_cmpxchg_long_func)(exchange_value, dest, compare_value); -} +DEFINE_STUB_CMPXCHG(1, jbyte, os::atomic_cmpxchg_byte_func) +DEFINE_STUB_CMPXCHG(4, jint, os::atomic_cmpxchg_func) +DEFINE_STUB_CMPXCHG(8, jlong, os::atomic_cmpxchg_long_func) -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, order); -} +#undef DEFINE_STUB_CMPXCHG inline jlong Atomic::load(const volatile jlong* src) { return *src; } #else // !AMD64 -inline jint Atomic::add (jint add_value, volatile jint* dest) { +template<> +template +inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const { + STATIC_ASSERT(4 == sizeof(I)); + STATIC_ASSERT(4 == sizeof(D)); __asm { mov edx, dest; mov eax, add_value; @@ -144,14 +152,6 @@ } } -inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { - return (intptr_t)add((jint)add_value, (volatile jint*)dest); -} - -inline void* Atomic::add_ptr(intptr_t add_value, volatile void* dest) { - return (void*)add((jint)add_value, (volatile jint*)dest); -} - inline void Atomic::inc (volatile jint* dest) { // alternative for InterlockedIncrement __asm { @@ -201,8 +201,13 @@ return (void*)xchg((jint)exchange_value, (volatile jint*)dest); } -#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE -inline jbyte Atomic::cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); // alternative for InterlockedCompareExchange __asm { mov edx, dest @@ -212,7 +217,13 @@ } } -inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); // alternative for InterlockedCompareExchange __asm { mov edx, dest @@ -222,7 +233,13 @@ } } -inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order) { +template<> +template +inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(8 == sizeof(T)); jint ex_lo = (jint)exchange_value; jint ex_hi = *( ((jint*)&exchange_value) + 1 ); jint cmp_lo = (jint)compare_value; @@ -241,14 +258,6 @@ } } -inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order) { - return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - -inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order) { - return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value, order); -} - inline jlong Atomic::load(const volatile jlong* src) { volatile jlong dest; volatile jlong* pdest = &dest; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/aot/aotCodeHeap.cpp --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -51,7 +51,7 @@ Klass* AOTCodeHeap::get_klass_from_got(const char* klass_name, int klass_len, const Method* method) { AOTKlassData* klass_data = (AOTKlassData*)_lib->load_symbol(klass_name); - Klass* k = (Klass*)_metaspace_got[klass_data->_got_index]; + Klass* k = (Klass*)_klasses_got[klass_data->_got_index]; if (k == NULL) { Thread* thread = Thread::current(); k = lookup_klass(klass_name, klass_len, method, thread); @@ -60,7 +60,7 @@ fatal("Shared file %s error: klass %s should be resolved already", _lib->name(), klass_name); vm_exit(1); } - _metaspace_got[klass_data->_got_index] = k; + _klasses_got[klass_data->_got_index] = k; } return k; } @@ -202,8 +202,8 @@ _name = (const char*) strdup(name); // Verify that VM runs with the same parameters as AOT tool. - _config = (AOTConfiguration*) load_symbol("JVM.config"); - _header = (AOTHeader*) load_symbol("JVM.header"); + _config = (AOTConfiguration*) load_symbol("A.config"); + _header = (AOTHeader*) load_symbol("A.header"); verify_config(); @@ -224,31 +224,31 @@ _method_count = _lib->header()->_method_count; // Collect metaspace info: names -> address in .got section - _metaspace_names = (const char*) _lib->load_symbol("JVM.meta.names"); - _method_metadata = (address) _lib->load_symbol("JVM.meth.metadata"); - _methods_offsets = (address) _lib->load_symbol("JVM.methods.offsets"); - _klasses_offsets = (address) _lib->load_symbol("JVM.kls.offsets"); - _dependencies = (address) _lib->load_symbol("JVM.kls.dependencies"); - _code_space = (address) _lib->load_symbol("JVM.text"); + _metaspace_names = (const char*) _lib->load_symbol("A.meta.names"); + _method_metadata = (address) _lib->load_symbol("A.meth.metadata"); + _methods_offsets = (address) _lib->load_symbol("A.meth.offsets"); + _klasses_offsets = (address) _lib->load_symbol("A.kls.offsets"); + _dependencies = (address) _lib->load_symbol("A.kls.dependencies"); + _code_space = (address) _lib->load_symbol("A.text"); // First cell is number of elements. - _metaspace_got = (Metadata**) _lib->load_symbol("JVM.meta.got"); - _metaspace_got_size = _lib->header()->_metaspace_got_size; + _klasses_got = (Metadata**) _lib->load_symbol("A.kls.got"); + _klasses_got_size = _lib->header()->_klasses_got_size; - _metadata_got = (Metadata**) _lib->load_symbol("JVM.metadata.got"); + _metadata_got = (Metadata**) _lib->load_symbol("A.meta.got"); _metadata_got_size = _lib->header()->_metadata_got_size; - _oop_got = (oop*) _lib->load_symbol("JVM.oop.got"); + _oop_got = (oop*) _lib->load_symbol("A.oop.got"); _oop_got_size = _lib->header()->_oop_got_size; // Collect stubs info - _stubs_offsets = (int*) _lib->load_symbol("JVM.stubs.offsets"); + _stubs_offsets = (int*) _lib->load_symbol("A.stubs.offsets"); // code segments table - _code_segments = (address) _lib->load_symbol("JVM.code.segments"); + _code_segments = (address) _lib->load_symbol("A.code.segments"); // method state - _method_state = (jlong*) _lib->load_symbol("JVM.meth.state"); + _method_state = (jlong*) _lib->load_symbol("A.meth.state"); // Create a table for mapping classes _classes = NEW_C_HEAP_ARRAY(AOTClass, _class_count, mtCode); @@ -316,7 +316,7 @@ AOTCompiledMethod *aot = new AOTCompiledMethod(code, mh(), meta, metadata_table, metadata_size, state_adr, this, name, code_id, _aot_id); assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized"); _code_to_aot[code_id]._aot = aot; // Should set this first - if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) { _code_to_aot[code_id]._aot = NULL; // Clean } else { // success // Publish method @@ -342,8 +342,8 @@ if (klass_data != NULL) { // Set both GOT cells, resolved and initialized klass pointers. // _got_index points to second cell - resolved klass pointer. - _metaspace_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized - _metaspace_got[klass_data->_got_index ] = (Metadata*)arr_klass; // Resolved + _klasses_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized + _klasses_got[klass_data->_got_index ] = (Metadata*)arr_klass; // Resolved if (PrintAOT) { tty->print_cr("[Found %s in %s]", arr_klass->internal_name(), _lib->name()); } @@ -378,7 +378,7 @@ AOTCompiledMethod* aot = new AOTCompiledMethod(entry, NULL, meta, metadata_table, metadata_size, state_adr, this, full_name, code_id, i); assert(_code_to_aot[code_id]._aot == NULL, "should be not initialized"); _code_to_aot[code_id]._aot = aot; - if (Atomic::cmpxchg(in_use, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(in_use, &_code_to_aot[code_id]._state, not_set) != not_set) { fatal("stab '%s' code state is %d", full_name, _code_to_aot[code_id]._state); } // Adjust code buffer boundaries only for stubs because they are last in the buffer. @@ -649,7 +649,7 @@ for (int i = 0; i < methods_cnt; ++i) { int code_id = indexes[i]; // Invalidate aot code. - if (Atomic::cmpxchg(invalid, (jint*)&_code_to_aot[code_id]._state, not_set) != not_set) { + if (Atomic::cmpxchg(invalid, &_code_to_aot[code_id]._state, not_set) != not_set) { if (_code_to_aot[code_id]._state == in_use) { AOTCompiledMethod* aot = _code_to_aot[code_id]._aot; assert(aot != NULL, "aot should be set"); @@ -680,16 +680,16 @@ if (!ik->has_passed_fingerprint_check()) { NOT_PRODUCT( aot_klasses_fp_miss++; ) log_trace(aot, class, fingerprint)("class %s%s has bad fingerprint in %s tid=" INTPTR_FORMAT, - ik->internal_name(), ik->is_shared() ? " (shared)" : "", - _lib->name(), p2i(thread)); + ik->internal_name(), ik->is_shared() ? " (shared)" : "", + _lib->name(), p2i(thread)); sweep_dependent_methods(klass_data); return false; } if (ik->has_been_redefined()) { log_trace(aot, class, load)("class %s%s in %s has been redefined tid=" INTPTR_FORMAT, - ik->internal_name(), ik->is_shared() ? " (shared)" : "", - _lib->name(), p2i(thread)); + ik->internal_name(), ik->is_shared() ? " (shared)" : "", + _lib->name(), p2i(thread)); sweep_dependent_methods(klass_data); return false; } @@ -698,7 +698,7 @@ AOTClass* aot_class = &_classes[klass_data->_class_id]; if (aot_class->_classloader != NULL && aot_class->_classloader != ik->class_loader_data()) { log_trace(aot, class, load)("class %s in %s already loaded for classloader %p vs %p tid=" INTPTR_FORMAT, - ik->internal_name(), _lib->name(), aot_class->_classloader, ik->class_loader_data(), p2i(thread)); + ik->internal_name(), _lib->name(), aot_class->_classloader, ik->class_loader_data(), p2i(thread)); NOT_PRODUCT( aot_klasses_cl_miss++; ) return false; } @@ -715,7 +715,7 @@ aot_class->_classloader = ik->class_loader_data(); // Set klass's Resolve (second) got cell. - _metaspace_got[klass_data->_got_index] = ik; + _klasses_got[klass_data->_got_index] = ik; // Initialize global symbols of the DSO to the corresponding VM symbol values. link_global_lib_symbols(); @@ -823,12 +823,12 @@ } } -// Scan only metaspace_got cells which should have only Klass*, +// Scan only klasses_got cells which should have only Klass*, // metadata_got cells are scanned only for alive AOT methods // by AOTCompiledMethod::metadata_do(). void AOTCodeHeap::got_metadata_do(void f(Metadata*)) { - for (int i = 1; i < _metaspace_got_size; i++) { - Metadata** p = &_metaspace_got[i]; + for (int i = 1; i < _klasses_got_size; i++) { + Metadata** p = &_klasses_got[i]; Metadata* md = *p; if (md == NULL) continue; // skip non-oops if (Metaspace::contains(md)) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/aot/aotCodeHeap.hpp --- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -26,6 +26,8 @@ #include "aot/aotCompiledMethod.hpp" #include "classfile/symbolTable.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/isRegisteredEnum.hpp" #include "oops/metadata.hpp" #include "oops/method.hpp" @@ -35,6 +37,8 @@ invalid = 2 // AOT code is invalidated because dependencies failed }; +template<> struct IsRegisteredEnum : public TrueType {}; + typedef struct { AOTCompiledMethod* _aot; CodeState _state; // State change cases: not_set->in_use, not_set->invalid @@ -77,7 +81,7 @@ int _version; int _class_count; int _method_count; - int _metaspace_got_size; + int _klasses_got_size; int _metadata_got_size; int _oop_got_size; int _jvm_version_offset; @@ -180,11 +184,11 @@ address _klasses_offsets; address _dependencies; - Metadata** _metaspace_got; + Metadata** _klasses_got; Metadata** _metadata_got; oop* _oop_got; - int _metaspace_got_size; + int _klasses_got_size; int _metadata_got_size; int _oop_got_size; @@ -251,7 +255,7 @@ #ifdef ASSERT bool got_contains(Metadata **p) { return (p >= &_metadata_got[0] && p < &_metadata_got[_metadata_got_size]) || - (p >= &_metaspace_got[0] && p < &_metaspace_got[_metaspace_got_size]); + (p >= &_klasses_got[0] && p < &_klasses_got[_klasses_got_size]); } #endif diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -491,7 +491,6 @@ } #ifdef ASSERT assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); - assert(exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); @@ -676,7 +675,6 @@ Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(thread, obj); - assert(h_obj()->is_oop(), "must be NULL or an object"); if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, lock->lock(), true, CHECK); @@ -701,7 +699,7 @@ EXCEPTION_MARK; oop obj = lock->obj(); - assert(obj->is_oop(), "must be NULL or an object"); + assert(oopDesc::is_oop(obj), "must be NULL or an object"); if (UseFastLocking) { // When using fast locking, the compiled code has already tried the fast case ObjectSynchronizer::slow_exit(obj, lock->lock(), THREAD); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -759,14 +759,18 @@ return metaspace; } -jobject ClassLoaderData::add_handle(Handle h) { +OopHandle ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); - return (jobject) _handles.add(h()); + return OopHandle(_handles.add(h())); } -void ClassLoaderData::remove_handle_unsafe(jobject h) { - assert(_handles.contains((oop*) h), "Got unexpected handle " PTR_FORMAT, p2i((oop*) h)); - *((oop*) h) = NULL; +void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) { + MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); + if (dest.resolve() != NULL) { + return; + } else { + dest = _handles.add(h()); + } } // Add this metadata pointer to be freed when it's safe. This is only during diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/classLoaderData.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -29,6 +29,7 @@ #include "memory/memRegion.hpp" #include "memory/metaspace.hpp" #include "memory/metaspaceCounters.hpp" +#include "oops/oopHandle.hpp" #include "runtime/mutex.hpp" #include "trace/traceMacros.hpp" #include "utilities/growableArray.hpp" @@ -362,8 +363,8 @@ void verify(); const char* loader_name(); - jobject add_handle(Handle h); - void remove_handle_unsafe(jobject h); + OopHandle add_handle(Handle h); + void init_handle_locked(OopHandle& pd, Handle h); // used for concurrent access to ModuleEntry::_pd field void add_class(Klass* k, bool publicize = true); void remove_class(Klass* k); bool contains_klass(Klass* k); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/classLoaderData.inline.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -41,7 +41,7 @@ inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) { - guarantee(loader() != NULL && loader()->is_oop(), "Loader must be oop"); + guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop"); // Gets the class loader data out of the java/lang/ClassLoader object, if non-null // it's already in the loader_data, so no need to add ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader()); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -799,7 +799,7 @@ // If java.base was already defined then patch this particular class with java.base. if (javabase_was_defined) { ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry(); - assert(javabase_entry != NULL && javabase_entry->module_handle() != NULL, + assert(javabase_entry != NULL && javabase_entry->module() != NULL, "Setting class module field, " JAVA_BASE_NAME " should be defined"); Handle javabase_handle(THREAD, javabase_entry->module()); set_module(mirror(), javabase_handle()); @@ -1430,7 +1430,7 @@ int java_lang_ThreadGroup::_ngroups_offset = 0; oop java_lang_ThreadGroup::parent(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->obj_field(_parent_offset); } @@ -1446,7 +1446,7 @@ } int java_lang_ThreadGroup::nthreads(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->int_field(_nthreads_offset); } @@ -1458,7 +1458,7 @@ } int java_lang_ThreadGroup::ngroups(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->int_field(_ngroups_offset); } @@ -1469,17 +1469,17 @@ } ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset); } bool java_lang_ThreadGroup::is_destroyed(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->bool_field(_destroyed_offset) != 0; } bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) { - assert(java_thread_group->is_oop(), "thread group must be oop"); + assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->bool_field(_daemon_offset) != 0; } @@ -2868,7 +2868,7 @@ ModuleEntry* java_lang_Module::module_entry(oop module, TRAPS) { assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); assert(module != NULL, "module can't be null"); - assert(module->is_oop(), "module must be oop"); + assert(oopDesc::is_oop(module), "module must be oop"); ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset); if (module_entry == NULL) { @@ -2885,7 +2885,7 @@ void java_lang_Module::set_module_entry(oop module, ModuleEntry* module_entry) { assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); assert(module != NULL, "module can't be null"); - assert(module->is_oop(), "module must be oop"); + assert(oopDesc::is_oop(module), "module must be oop"); module->address_field_put(_module_entry_offset, (address)module_entry); } @@ -3088,12 +3088,9 @@ oop java_lang_invoke_DirectMethodHandle::member(oop dmh) { oop member_name = NULL; - bool is_dmh = dmh->is_oop() && java_lang_invoke_DirectMethodHandle::is_instance(dmh); - assert(is_dmh, "a DirectMethodHandle oop is expected"); - if (is_dmh) { - member_name = dmh->obj_field(member_offset_in_bytes()); - } - return member_name; + assert(oopDesc::is_oop(dmh) && java_lang_invoke_DirectMethodHandle::is_instance(dmh), + "a DirectMethodHandle oop is expected"); + return dmh->obj_field(member_offset_in_bytes()); } void java_lang_invoke_DirectMethodHandle::compute_offsets() { @@ -3476,7 +3473,7 @@ int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { - assert(loader != NULL && loader->is_oop(), "loader must be oop"); + assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop"); return (ClassLoaderData**) loader->address_field_addr(_loader_data_offset); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/moduleEntry.cpp --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -80,19 +80,16 @@ } // Returns the shared ProtectionDomain -Handle ModuleEntry::shared_protection_domain() { - return Handle(Thread::current(), JNIHandles::resolve(_pd)); +oop ModuleEntry::shared_protection_domain() { + return _pd.resolve(); } // Set the shared ProtectionDomain atomically void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd_h) { // Create a handle for the shared ProtectionDomain and save it atomically. - // If someone beats us setting the _pd cache, the created handle is destroyed. - jobject obj = loader_data->add_handle(pd_h); - if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) { - loader_data->remove_handle_unsafe(obj); - } + // init_handle_locked checks if someone beats us setting the _pd cache. + loader_data->init_handle_locked(_pd, pd_h); } // Returns true if this module can read module m diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/moduleEntry.hpp --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -27,6 +27,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/vmSymbols.hpp" +#include "oops/oopHandle.hpp" #include "oops/symbol.hpp" #include "prims/jni.h" #include "runtime/jniHandles.hpp" @@ -56,8 +57,8 @@ // data structure. class ModuleEntry : public HashtableEntry { private: - jobject _module; // java.lang.Module - jobject _pd; // java.security.ProtectionDomain, cached + OopHandle _module; // java.lang.Module + OopHandle _pd; // java.security.ProtectionDomain, cached // for shared classes from this module ClassLoaderData* _loader_data; GrowableArray* _reads; // list of modules that are readable by this module @@ -89,16 +90,16 @@ Symbol* name() const { return literal(); } void set_name(Symbol* n) { set_literal(n); } - oop module() const { return JNIHandles::resolve(_module); } - jobject module_handle() const { return _module; } - void set_module(jobject j) { _module = j; } + oop module() const { return _module.resolve(); } + OopHandle module_handle() const { return _module; } + void set_module(OopHandle j) { _module = j; } // The shared ProtectionDomain reference is set once the VM loads a shared class // originated from the current Module. The referenced ProtectionDomain object is // created by the ClassLoader when loading a class (shared or non-shared) from the // Module for the first time. This ProtectionDomain object is used for all // classes from the Module loaded by the same ClassLoader. - Handle shared_protection_domain(); + oop shared_protection_domain(); void set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd); ClassLoaderData* loader_data() const { return _loader_data; } @@ -246,7 +247,7 @@ static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; } static bool javabase_defined() { return ((_javabase_module != NULL) && - (_javabase_module->module_handle() != NULL)); } + (_javabase_module->module() != NULL)); } static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location); static void patch_javabase_entries(Handle module_handle); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/protectionDomainCache.cpp --- a/hotspot/src/share/vm/classfile/protectionDomainCache.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/protectionDomainCache.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -97,7 +97,7 @@ } void ProtectionDomainCacheEntry::verify() { - guarantee(literal()->is_oop(), "must be an oop"); + guarantee(oopDesc::is_oop(literal()), "must be an oop"); } ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -77,9 +77,8 @@ #include "services/classLoadingService.hpp" #include "services/diagnosticCommand.hpp" #include "services/threadService.hpp" -#include "trace/traceMacros.hpp" +#include "trace/tracing.hpp" #include "utilities/macros.hpp" -#include "utilities/ticks.hpp" #if INCLUDE_CDS #include "classfile/sharedClassUtil.hpp" #include "classfile/systemDictionaryShared.hpp" @@ -87,9 +86,6 @@ #if INCLUDE_JVMCI #include "jvmci/jvmciRuntime.hpp" #endif -#if INCLUDE_TRACE -#include "trace/tracing.hpp" -#endif PlaceholderTable* SystemDictionary::_placeholders = NULL; Dictionary* SystemDictionary::_shared_dictionary = NULL; @@ -615,17 +611,17 @@ return NULL; } -static void post_class_load_event(const Ticks& start_time, - InstanceKlass* k, +static void post_class_load_event(EventClassLoad* event, + const InstanceKlass* k, const ClassLoaderData* init_cld) { #if INCLUDE_TRACE - EventClassLoad event(UNTIMED); - if (event.should_commit()) { - event.set_starttime(start_time); - event.set_loadedClass(k); - event.set_definingClassLoader(k->class_loader_data()); - event.set_initiatingClassLoader(init_cld); - event.commit(); + assert(event != NULL, "invariant"); + assert(k != NULL, "invariant"); + if (event->should_commit()) { + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); } #endif // INCLUDE_TRACE } @@ -653,7 +649,7 @@ assert(name != NULL && !FieldType::is_array(name) && !FieldType::is_obj(name), "invalid class name"); - Ticks class_load_start_time = Ticks::now(); + EventClassLoad class_load_start_event; HandleMark hm(THREAD); @@ -899,7 +895,7 @@ return NULL; } - post_class_load_event(class_load_start_time, k, loader_data); + post_class_load_event(&class_load_start_event, k, loader_data); #ifdef ASSERT { @@ -1006,7 +1002,7 @@ GrowableArray* cp_patches, TRAPS) { - Ticks class_load_start_time = Ticks::now(); + EventClassLoad class_load_start_event; ClassLoaderData* loader_data; if (host_klass != NULL) { @@ -1064,7 +1060,7 @@ JvmtiExport::post_class_load((JavaThread *) THREAD, k); } - post_class_load_event(class_load_start_time, k, loader_data); + post_class_load_event(&class_load_start_event, k, loader_data); } assert(host_klass != NULL || NULL == cp_patches, "cp_patches only found with host_klass"); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/code/debugInfo.cpp --- a/hotspot/src/share/vm/code/debugInfo.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/code/debugInfo.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -48,7 +48,7 @@ oop DebugInfoReadStream::read_oop() { oop o = code()->oop_at(read_int()); - assert(o->is_oop_or_null(), "oop only"); + assert(oopDesc::is_oop_or_null(o), "oop only"); return o; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/code/dependencies.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -940,7 +940,7 @@ oop Dependencies::DepStream::argument_oop(int i) { oop result = recorded_oop_at(argument_index(i)); - assert(result == NULL || result->is_oop(), "must be"); + assert(oopDesc::is_oop_or_null(result), "must be"); return result; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/code/nmethod.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -2090,7 +2090,7 @@ VerifyOopsClosure(nmethod* nm) : _nm(nm), _ok(true) { } bool ok() { return _ok; } virtual void do_oop(oop* p) { - if ((*p) == NULL || (*p)->is_oop()) return; + if (oopDesc::is_oop_or_null(*p)) return; if (_ok) { _nm->print_nmethod(true); _ok = false; @@ -2112,7 +2112,7 @@ // Make sure all the entry points are correctly aligned for patching. NativeJump::check_verified_entry_alignment(entry_point(), verified_entry_point()); - // assert(method()->is_oop(), "must be valid"); + // assert(oopDesc::is_oop(method()), "must be valid"); ResourceMark rm; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/code/relocInfo.cpp --- a/hotspot/src/share/vm/code/relocInfo.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/code/relocInfo.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -867,7 +867,7 @@ // work even during GC or other inconvenient times. if (WizardMode && oop_value != NULL) { tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value)); - if (oop_value->is_oop()) { + if (oopDesc::is_oop(oop_value)) { oop_value->print_value_on(tty); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -720,44 +720,49 @@ // At this point it may be possible that no osthread was created for the // JavaThread due to lack of memory. We would have to throw an exception // in that case. However, since this must work and we do not allow - // exceptions anyway, check and abort if this fails. + // exceptions anyway, check and abort if this fails. But first release the + // lock. - if (thread == NULL || thread->osthread() == NULL) { - vm_exit_during_initialization("java.lang.OutOfMemoryError", - os::native_thread_creation_failed_msg()); - } + if (thread != NULL && thread->osthread() != NULL) { + + java_lang_Thread::set_thread(thread_oop(), thread); - java_lang_Thread::set_thread(thread_oop(), thread); + // Note that this only sets the JavaThread _priority field, which by + // definition is limited to Java priorities and not OS priorities. + // The os-priority is set in the CompilerThread startup code itself - // Note that this only sets the JavaThread _priority field, which by - // definition is limited to Java priorities and not OS priorities. - // The os-priority is set in the CompilerThread startup code itself + java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); - java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); + // Note that we cannot call os::set_priority because it expects Java + // priorities and we are *explicitly* using OS priorities so that it's + // possible to set the compiler thread priority higher than any Java + // thread. - // Note that we cannot call os::set_priority because it expects Java - // priorities and we are *explicitly* using OS priorities so that it's - // possible to set the compiler thread priority higher than any Java - // thread. - - int native_prio = CompilerThreadPriority; - if (native_prio == -1) { - if (UseCriticalCompilerThreadPriority) { - native_prio = os::java_to_os_priority[CriticalPriority]; - } else { - native_prio = os::java_to_os_priority[NearMaxPriority]; + int native_prio = CompilerThreadPriority; + if (native_prio == -1) { + if (UseCriticalCompilerThreadPriority) { + native_prio = os::java_to_os_priority[CriticalPriority]; + } else { + native_prio = os::java_to_os_priority[NearMaxPriority]; + } } - } - os::set_native_priority(thread, native_prio); + os::set_native_priority(thread, native_prio); - java_lang_Thread::set_daemon(thread_oop()); + java_lang_Thread::set_daemon(thread_oop()); - thread->set_threadObj(thread_oop()); - if (compiler_thread) { - thread->as_CompilerThread()->set_compiler(comp); + thread->set_threadObj(thread_oop()); + if (compiler_thread) { + thread->as_CompilerThread()->set_compiler(comp); + } + Threads::add(thread); + Thread::start(thread); } - Threads::add(thread); - Thread::start(thread); + } + + // First release lock before aborting VM. + if (thread == NULL || thread->osthread() == NULL) { + vm_exit_during_initialization("java.lang.OutOfMemoryError", + os::native_thread_creation_failed_msg()); } // Let go of Threads_lock before yielding diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp --- a/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -74,7 +74,7 @@ while (_work_queue->size() > max) { oop newOop; if (_work_queue->pop_local(newOop)) { - assert(newOop->is_oop(), "Expected an oop"); + assert(oopDesc::is_oop(newOop), "Expected an oop"); assert(_bit_map->isMarked((HeapWord*)newOop), "only grey objects on this stack"); // iterate over the oops in this oop, marking and pushing diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -929,7 +929,7 @@ if (k != NULL) { assert(k->is_klass(), "Should really be klass oop."); oop o = (oop)p; - assert(o->is_oop(true /* ignore mark word */), "Should be an oop."); + assert(oopDesc::is_oop(o, true /* ignore mark word */), "Should be an oop."); size_t res = o->size_given_klass(k); res = adjustObjectSize(res); @@ -979,7 +979,7 @@ if (k != NULL) { assert(k->is_klass(), "Should really be klass oop."); oop o = (oop)p; - assert(o->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(o), "Should be an oop"); size_t res = o->size_given_klass(k); res = adjustObjectSize(res); @@ -1005,7 +1005,7 @@ // Ignore mark word because this may be a recently promoted // object whose mark word is used to chain together grey // objects (the last one would have a null value). - assert(oop(p)->is_oop(true), "Should be an oop"); + assert(oopDesc::is_oop(oop(p), true), "Should be an oop"); return adjustObjectSize(oop(p)->size()); } } @@ -1022,7 +1022,7 @@ // Ignore mark word because it may have been used to // chain together promoted objects (the last one // would have a null value). - assert(oop(p)->is_oop(true), "Should be an oop"); + assert(oopDesc::is_oop(oop(p), true), "Should be an oop"); return true; } else { return false; // Was not an object at the start of collection. @@ -1066,7 +1066,7 @@ // Ignore mark word because it may have been used to // chain together promoted objects (the last one // would have a null value). - assert(oop(p)->is_oop(true), "Should be an oop"); + assert(oopDesc::is_oop(oop(p), true), "Should be an oop"); return true; } return false; @@ -2174,7 +2174,7 @@ if (_sp->block_is_obj(addr)) { was_obj = true; oop p = oop(addr); - guarantee(p->is_oop(), "Should be an oop"); + guarantee(oopDesc::is_oop(p), "Should be an oop"); res = _sp->adjustObjectSize(p->size()); if (_sp->obj_is_alive(addr)) { was_live = true; @@ -2226,7 +2226,7 @@ guarantee(!_sp->is_in_reserved(obj) || _sp->block_is_obj((HeapWord*)obj), "Should be an object"); - guarantee(obj->is_oop(), "Should be an oop"); + guarantee(oopDesc::is_oop(obj), "Should be an oop"); obj->verify(); if (_past_remark) { // Remark has been completed, the object should be marked @@ -2243,7 +2243,7 @@ } } else if (_sp->is_in_reserved(p)) { // the reference is from FLS, and points out of FLS - guarantee(obj->is_oop(), "Should be an oop"); + guarantee(oopDesc::is_oop(obj), "Should be an oop"); obj->verify(); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -940,7 +940,7 @@ if (res != NULL) { // See comment in allocate() about when objects should // be allocated live. - assert(obj->is_oop(), "Will dereference klass pointer below"); + assert(oopDesc::is_oop(obj), "Will dereference klass pointer below"); collector()->promoted(false, // Not parallel (HeapWord*)res, obj->is_objArray(), obj_size); // promotion counters @@ -1063,13 +1063,13 @@ } assert(obj->klass_or_null() == NULL, "Object should be uninitialized here."); assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size"); - assert(old->is_oop(), "Will use and dereference old klass ptr below"); + assert(oopDesc::is_oop(old), "Will use and dereference old klass ptr below"); // Finally, install the klass pointer (this should be volatile). OrderAccess::storestore(); obj->set_klass(old->klass()); // We should now be able to calculate the right size for this object - assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object"); + assert(oopDesc::is_oop(obj) && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object"); collector()->promoted(true, // parallel obj_ptr, old->is_objArray(), word_sz); @@ -3348,7 +3348,7 @@ // been published), so we do not need to check for // uninitialized objects before pushing here. void ParConcMarkingClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); + assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -3390,7 +3390,7 @@ while (_work_queue->size() > max) { oop new_oop; if (_work_queue->pop_local(new_oop)) { - assert(new_oop->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(new_oop), "Should be an oop"); assert(_bit_map->isMarked((HeapWord*)new_oop), "Grey object"); assert(_span.contains((HeapWord*)new_oop), "Not in span"); new_oop->oop_iterate(this); // do_oop() above @@ -3431,7 +3431,7 @@ // assert(work_q->size() > 0, "Work from overflow stack"); continue; } else if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) { - assert(obj_to_scan->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(obj_to_scan), "Should be an oop"); assert(bm->isMarked((HeapWord*)obj_to_scan), "Grey object"); obj_to_scan->oop_iterate(&cl); } else if (terminator()->offer_termination(&_term_term)) { @@ -4522,7 +4522,7 @@ assert(mr.is_empty() || space->used_region().contains(mr), "Should be in space"); // Verify that "start" is an object boundary - assert(mr.is_empty() || oop(mr.start())->is_oop(), + assert(mr.is_empty() || oopDesc::is_oop(oop(mr.start())), "Should be an oop"); space->par_oop_iterate(mr, cl); } @@ -4656,7 +4656,7 @@ // Try to steal from other queues that have work if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) { NOT_PRODUCT(num_steals++;) - assert(obj_to_scan->is_oop(), "Oops, not an oop!"); + assert(oopDesc::is_oop(obj_to_scan), "Oops, not an oop!"); assert(bm->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?"); // Do scanning work obj_to_scan->oop_iterate(cl); @@ -5135,7 +5135,7 @@ // Try to steal from other queues that have work if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) { NOT_PRODUCT(num_steals++;) - assert(obj_to_scan->is_oop(), "Oops, not an oop!"); + assert(oopDesc::is_oop(obj_to_scan), "Oops, not an oop!"); assert(_mark_bit_map->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?"); // Do scanning work obj_to_scan->oop_iterate(keep_alive); @@ -5825,7 +5825,7 @@ void MarkRefsIntoClosure::do_oop(oop obj) { // if p points into _span, then mark corresponding bit in _markBitMap - assert(obj->is_oop(), "expected an oop"); + assert(oopDesc::is_oop(obj), "expected an oop"); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr)) { // this should be made more efficient @@ -5847,7 +5847,7 @@ void ParMarkRefsIntoClosure::do_oop(oop obj) { // if p points into _span, then mark corresponding bit in _markBitMap - assert(obj->is_oop(), "expected an oop"); + assert(oopDesc::is_oop(obj), "expected an oop"); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr)) { // this should be made more efficient @@ -5871,7 +5871,7 @@ void MarkRefsIntoVerifyClosure::do_oop(oop obj) { // if p points into _span, then mark corresponding bit in _markBitMap - assert(obj->is_oop(), "expected an oop"); + assert(oopDesc::is_oop(obj), "expected an oop"); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr)) { _verification_bm->mark(addr); @@ -5925,7 +5925,7 @@ // The parallel version (Par_...) appears further below. void MarkRefsIntoAndScanClosure::do_oop(oop obj) { if (obj != NULL) { - assert(obj->is_oop(), "expected an oop"); + assert(oopDesc::is_oop(obj), "expected an oop"); HeapWord* addr = (HeapWord*)obj; assert(_mark_stack->isEmpty(), "pre-condition (eager drainage)"); assert(_collector->overflow_list_is_empty(), @@ -5941,7 +5941,7 @@ assert(res, "Should have space to push on empty stack"); do { oop new_oop = _mark_stack->pop(); - assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop"); + assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop"); assert(_bit_map->isMarked((HeapWord*)new_oop), "only grey objects on this stack"); // iterate over the oops in this oop, marking and pushing @@ -6023,7 +6023,7 @@ if (obj != NULL) { // Ignore mark word because this could be an already marked oop // that may be chained at the end of the overflow list. - assert(obj->is_oop(true), "expected an oop"); + assert(oopDesc::is_oop(obj, true), "expected an oop"); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_bit_map->isMarked(addr)) { @@ -6069,7 +6069,7 @@ if (p->klass_or_null_acquire() != NULL) { // an initialized object; ignore mark word in verification below // since we are running concurrent with mutators - assert(p->is_oop(true), "should be an oop"); + assert(oopDesc::is_oop(p, true), "should be an oop"); if (p->is_objArray()) { // objArrays are precisely marked; restrict scanning // to dirty cards only. @@ -6118,7 +6118,7 @@ } else { // An object not (yet) reached by marking: we merely need to // compute its size so as to go look at the next block. - assert(p->is_oop(true), "should be an oop"); + assert(oopDesc::is_oop(p, true), "should be an oop"); size = CompactibleFreeListSpace::adjustObjectSize(p->size()); } } @@ -6165,7 +6165,7 @@ assert(p->klass_or_null() != NULL, "object should be initialized"); // an initialized object; ignore mark word in verification below // since we are running concurrent with mutators - assert(p->is_oop(true), "should be an oop"); + assert(oopDesc::is_oop(p, true), "should be an oop"); // Note that we do not yield while we iterate over // the interior oops of p, pushing the relevant ones // on our marking stack. @@ -6179,7 +6179,7 @@ // from the grey objects at a later time. while (!_mark_stack->isEmpty()) { oop new_oop = _mark_stack->pop(); - assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop"); + assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop"); assert(_bit_map->isMarked((HeapWord*)new_oop), "only grey objects on this stack"); // iterate over the oops in this oop, marking and pushing @@ -6223,7 +6223,7 @@ // isMarked() query is "safe". bool ScanMarkedObjectsAgainClosure::do_object_bm(oop p, MemRegion mr) { // Ignore mark word because we are running concurrent with mutators - assert(p->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p)); + assert(oopDesc::is_oop_or_null(p, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p)); HeapWord* addr = (HeapWord*)p; assert(_span.contains(addr), "we are scanning the CMS generation"); bool is_obj_array = false; @@ -6376,7 +6376,7 @@ oop obj = oop(ptr); // Ignore mark word in verification below, since we // may be running concurrent with mutators. - assert(obj->is_oop(true), "should be an oop"); + assert(oopDesc::is_oop(obj, true), "should be an oop"); assert(_finger <= ptr, "_finger runneth ahead"); // advance the finger to right end of this object _finger = ptr + obj->size(); @@ -6423,7 +6423,7 @@ oop new_oop = _markStack->pop(); // Skip verifying header mark word below because we are // running concurrent with mutators. - assert(new_oop->is_oop(true), "Oops! expected to pop an oop"); + assert(oopDesc::is_oop(new_oop, true), "Oops! expected to pop an oop"); // now scan this oop's oops new_oop->oop_iterate(&pushOrMarkClosure); do_yield_check(); @@ -6489,7 +6489,7 @@ oop obj = oop(ptr); // Ignore mark word in verification below, since we // may be running concurrent with mutators. - assert(obj->is_oop(true), "should be an oop"); + assert(oopDesc::is_oop(obj, true), "should be an oop"); assert(_finger <= ptr, "_finger runneth ahead"); // advance the finger to right end of this object _finger = ptr + obj->size(); @@ -6550,7 +6550,7 @@ } // Skip verifying header mark word below because we are // running concurrent with mutators. - assert(new_oop->is_oop(true), "Oops! expected to pop an oop"); + assert(oopDesc::is_oop(new_oop, true), "Oops! expected to pop an oop"); // now scan this oop's oops new_oop->oop_iterate(&pushOrMarkClosure); do_yield_check(); @@ -6604,7 +6604,7 @@ "should drain stack to limit stack usage"); // convert addr to an oop preparatory to scanning oop obj = oop(addr); - assert(obj->is_oop(), "should be an oop"); + assert(oopDesc::is_oop(obj), "should be an oop"); assert(_finger <= addr, "_finger runneth ahead"); // advance the finger to right end of this object _finger = addr + obj->size(); @@ -6615,7 +6615,7 @@ assert(res, "Empty non-zero size stack should have space for single push"); while (!_mark_stack->isEmpty()) { oop new_oop = _mark_stack->pop(); - assert(new_oop->is_oop(), "Oops! expected to pop an oop"); + assert(oopDesc::is_oop(new_oop), "Oops! expected to pop an oop"); // now scan this oop's oops new_oop->oop_iterate(&_pam_verify_closure); } @@ -6650,7 +6650,7 @@ } void PushAndMarkVerifyClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); + assert(oopDesc::is_oop_or_null(obj), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_verification_bm->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -6747,7 +6747,7 @@ void PushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); + assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_bitMap->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -6782,7 +6782,7 @@ void ParPushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); + assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_whole_span.contains(addr) && !_bit_map->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -6855,7 +6855,7 @@ // phases, the object may already have been reached by a different // path and may be at the end of the global overflow list (so // the mark word may be NULL). - assert(obj->is_oop_or_null(true /* ignore mark word */), + assert(oopDesc::is_oop_or_null(obj, true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation @@ -6934,7 +6934,7 @@ // value, by the time we get to examined this failing assert in // the debugger, is_oop_or_null(false) may subsequently start // to hold. - assert(obj->is_oop_or_null(true), + assert(oopDesc::is_oop_or_null(obj, true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation @@ -7325,7 +7325,7 @@ // This object is live: we'd normally expect this to be // an oop, and like to assert the following: - // assert(oop(addr)->is_oop(), "live block should be an oop"); + // assert(oopDesc::is_oop(oop(addr)), "live block should be an oop"); // However, as we commented above, this may be an object whose // header hasn't yet been initialized. size_t size; @@ -7341,7 +7341,7 @@ #ifdef ASSERT if (oop(addr)->klass_or_null_acquire() != NULL) { // Ignore mark word because we are running concurrent with mutators - assert(oop(addr)->is_oop(true), "live block should be an oop"); + assert(oopDesc::is_oop(oop(addr), true), "live block should be an oop"); assert(size == CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()), "P-mark and computed size do not agree"); @@ -7353,7 +7353,7 @@ assert(oop(addr)->klass_or_null_acquire() != NULL, "Should be an initialized object"); // Ignore mark word because we are running concurrent with mutators - assert(oop(addr)->is_oop(true), "live block should be an oop"); + assert(oopDesc::is_oop(oop(addr), true), "live block should be an oop"); // Verify that the bit map has no bits marked between // addr and purported end of this block. size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()); @@ -7661,7 +7661,7 @@ while (_work_queue->size() > max) { oop new_oop; if (_work_queue->pop_local(new_oop)) { - assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop"); + assert(new_oop != NULL && oopDesc::is_oop(new_oop), "Expected an oop"); assert(_bit_map->isMarked((HeapWord*)new_oop), "no white objects on this stack!"); assert(_span.contains((HeapWord*)new_oop), "Out of bounds oop"); @@ -7741,7 +7741,7 @@ HeapWord* addr = (HeapWord*)obj; assert(_span.contains(addr), "Should be within span"); assert(_bit_map->isMarked(addr), "Should be marked"); - assert(obj->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(obj), "Should be an oop"); obj->oop_iterate(_keep_alive); } } @@ -7756,7 +7756,7 @@ while (_work_queue->size() > max) { oop new_oop; if (_work_queue->pop_local(new_oop)) { - assert(new_oop->is_oop(), "Expected an oop"); + assert(oopDesc::is_oop(new_oop), "Expected an oop"); assert(_bit_map->isMarked((HeapWord*)new_oop), "no white objects on this stack!"); assert(_span.contains((HeapWord*)new_oop), "Out of bounds oop"); @@ -7807,7 +7807,7 @@ for (oop next; i > 0 && cur != NULL; cur = next, i--) { next = oop(cur->mark()); cur->set_mark(proto); // until proven otherwise - assert(cur->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(cur), "Should be an oop"); bool res = stack->push(cur); assert(res, "Bit off more than can chew?"); NOT_PRODUCT(n++;) @@ -7951,7 +7951,7 @@ for (cur = prefix; cur != NULL; cur = next) { next = oop(cur->mark()); cur->set_mark(proto); // until proven otherwise - assert(cur->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(cur), "Should be an oop"); bool res = work_q->push(cur); assert(res, "Bit off more than we can chew?"); NOT_PRODUCT(n++;) @@ -7966,7 +7966,7 @@ // Single-threaded void CMSCollector::push_on_overflow_list(oop p) { NOT_PRODUCT(_num_par_pushes++;) - assert(p->is_oop(), "Not an oop"); + assert(oopDesc::is_oop(p), "Not an oop"); preserve_mark_if_necessary(p); p->set_mark((markOop)_overflow_list); _overflow_list = p; @@ -7975,7 +7975,7 @@ // Multi-threaded; use CAS to prepend to overflow list void CMSCollector::par_push_on_overflow_list(oop p) { NOT_PRODUCT(Atomic::inc_ptr(&_num_par_pushes);) - assert(p->is_oop(), "Not an oop"); + assert(oopDesc::is_oop(p), "Not an oop"); par_preserve_mark_if_necessary(p); oop observed_overflow_list = _overflow_list; oop cur_overflow_list; @@ -8062,7 +8062,7 @@ while (!_preserved_oop_stack.is_empty()) { oop p = _preserved_oop_stack.pop(); - assert(p->is_oop(), "Should be an oop"); + assert(oopDesc::is_oop(p), "Should be an oop"); assert(_span.contains(p), "oop should be in _span"); assert(p->mark() == markOopDesc::prototype(), "Set when taken from overflow list"); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/cms/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -684,7 +684,7 @@ oop obj = oopDesc::load_decode_heap_oop_not_null(p); // We never expect to see a null reference being processed // as a weak reference. - assert(obj->is_oop(), "expected an oop while scanning weak refs"); + assert(oopDesc::is_oop(obj), "expected an oop while scanning weak refs"); } #endif // ASSERT @@ -711,7 +711,7 @@ oop obj = oopDesc::load_decode_heap_oop_not_null(p); // We never expect to see a null reference being processed // as a weak reference. - assert(obj->is_oop(), "expected an oop while scanning weak refs"); + assert(oopDesc::is_oop(obj), "expected an oop while scanning weak refs"); } #endif // ASSERT diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/cms/promotionInfo.cpp --- a/hotspot/src/share/vm/gc/cms/promotionInfo.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -43,7 +43,7 @@ } else { res = (PromotedObject*)(_next & next_mask); } - assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res))); + assert(oopDesc::is_oop_or_null(oop(res), true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res))); return res; } @@ -299,7 +299,7 @@ for (PromotedObject* curObj = _promoHead; curObj != NULL; curObj = curObj->next()) { guarantee(space()->is_in_reserved((HeapWord*)curObj), "Containment"); // the last promoted object may fail the mark() != NULL test of is_oop(). - guarantee(curObj->next() == NULL || oop(curObj)->is_oop(), "must be an oop"); + guarantee(curObj->next() == NULL || oopDesc::is_oop(oop(curObj)), "must be an oop"); if (curObj->hasDisplacedMark()) { numObjsWithDisplacedHdrs++; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp --- a/hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -409,7 +409,7 @@ virtual void work(uint worker_id) { while (true) { - size_t to_process = Atomic::add(1, &_cur_chunk) - 1; + size_t to_process = Atomic::add(1u, &_cur_chunk) - 1; if (to_process >= _num_chunks) { break; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -200,7 +200,7 @@ return NULL; } - size_t cur_idx = Atomic::add(1, &_hwm) - 1; + size_t cur_idx = Atomic::add(1u, &_hwm) - 1; if (cur_idx >= _chunk_capacity) { return NULL; } @@ -1918,7 +1918,7 @@ guarantee(_g1h->is_in_reserved(task_entry.slice()), "Slice " PTR_FORMAT " must be in heap.", p2i(task_entry.slice())); return; } - guarantee(task_entry.obj()->is_oop(), + guarantee(oopDesc::is_oop(task_entry.obj()), "Non-oop " PTR_FORMAT ", phase: %s, info: %d", p2i(task_entry.obj()), _phase, _info); guarantee(!_g1h->is_in_cset(task_entry.obj()), @@ -2313,7 +2313,7 @@ if (task_entry.is_null()) { break; } - assert(task_entry.is_array_slice() || task_entry.obj()->is_oop(), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj())); + assert(task_entry.is_array_slice() || oopDesc::is_oop(task_entry.obj()), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj())); bool success = _task_queue->push(task_entry); // We only call this when the local queue is empty or under a // given target limit. So, we do not expect this push to fail. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -217,7 +217,7 @@ } bool G1ConcurrentMark::isPrevMarked(oop p) const { - assert(p != NULL && p->is_oop(), "expected an oop"); + assert(p != NULL && oopDesc::is_oop(p), "expected an oop"); return _prevMarkBitMap->is_marked((HeapWord*)p); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -64,7 +64,7 @@ return card_ptr; } // Otherwise, the card is hot. - size_t index = Atomic::add(1, &_hot_cache_idx) - 1; + size_t index = Atomic::add(1u, &_hot_cache_idx) - 1; size_t masked_index = index & (_hot_cache_size - 1); jbyte* current_ptr = _hot_cache[masked_index]; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -67,7 +67,7 @@ size_t _hot_cache_size; - int _hot_cache_par_chunk_size; + size_t _hot_cache_par_chunk_size; // Avoids false sharing when concurrently updating _hot_cache_idx or // _hot_cache_par_claimed_idx. These are never updated at the same time diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -107,7 +107,7 @@ #ifdef ASSERT G1CollectedHeap* g1 = G1CollectedHeap::heap(); // can't do because of races - // assert(obj == NULL || obj->is_oop(), "expected an oop"); + // assert(oopDesc::is_oop_or_null(obj), "expected an oop"); assert(check_obj_alignment(obj), "not oop aligned"); assert(g1->is_in_reserved(obj), "must be in heap"); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -243,7 +243,7 @@ bool marked_as_dirty = Atomic::cmpxchg(Dirty, &_in_dirty_region_buffer[region], Clean) == Clean; if (marked_as_dirty) { - size_t allocated = Atomic::add(1, &_cur_dirty_region) - 1; + size_t allocated = Atomic::add(1u, &_cur_dirty_region) - 1; _dirty_region_buffer[allocated] = region; } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -39,7 +39,7 @@ #ifdef ASSERT // can't do because of races - // assert(obj == NULL || obj->is_oop(), "expected an oop"); + // assert(oopDesc::is_oop_or_null(obj), "expected an oop"); assert(check_obj_alignment(obj), "not oop aligned"); assert(_g1->is_in_reserved(obj), "must be in heap"); #endif // ASSERT diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -43,7 +43,7 @@ void G1SATBCardTableModRefBS::enqueue(oop pre_val) { // Nulls should have been already filtered. - assert(pre_val->is_oop(true), "Error"); + assert(oopDesc::is_oop(pre_val, true), "Error"); if (!JavaThread::satb_mark_queue_set().is_active()) return; Thread* thr = Thread::current(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -610,7 +610,7 @@ LogStream ls(log.error()); _containing_obj->print_on(&ls); log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); - if (obj->is_oop()) { + if (oopDesc::is_oop(obj)) { obj->print_on(&ls); } log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); @@ -657,7 +657,7 @@ object_num += 1; if (!g1->is_obj_dead_cond(obj, this, vo)) { - if (obj->is_oop()) { + if (oopDesc::is_oop(obj)) { Klass* klass = obj->klass(); bool is_metaspace_object = Metaspace::contains(klass) || (vo == VerifyOption_G1UsePrevMarking && @@ -803,7 +803,7 @@ size_t obj_size = block_size(p); if (!g1->is_obj_dead_cond(obj, this, vo)) { - if (obj->is_oop()) { + if (oopDesc::is_oop(obj)) { vr_cl.set_containing_obj(obj); obj->oop_iterate_no_header(&vr_cl); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -337,7 +337,7 @@ const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prevMarkBitMap(); do { oop obj = oop(cur); - assert(obj->is_oop(true), "Not an oop at " PTR_FORMAT, p2i(cur)); + assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); assert(obj->klass_or_null() != NULL, "Unparsable heap at " PTR_FORMAT, p2i(cur)); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -95,7 +95,7 @@ return false; } - assert(((oop)entry)->is_oop(true /* ignore mark word */), + assert(oopDesc::is_oop(oop(entry), true /* ignore mark word */), "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry)); return true; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -287,7 +287,7 @@ while (p < to) { Prefetch::write(p, interval); oop m = oop(p); - assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); + assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } @@ -295,7 +295,7 @@ } else { while (p < to) { oop m = oop(p); - assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); + assert(oopDesc::is_oop_or_null(m), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -2597,7 +2597,7 @@ start_array->allocate_block(addr); } cm->update_contents(oop(addr)); - assert(oop(addr)->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr))); + assert(oopDesc::is_oop_or_null(oop(addr)), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr))); } } } @@ -3144,7 +3144,7 @@ oop moved_oop = (oop) destination(); compaction_manager()->update_contents(moved_oop); - assert(moved_oop->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop)); + assert(oopDesc::is_oop_or_null(moved_oop), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop)); update_state(words); assert(destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity"); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -593,9 +593,8 @@ inline bool ParallelCompactData::RegionData::claim() { - const int los = (int) live_obj_size(); - const int old = Atomic::cmpxchg(dc_claimed | los, - (volatile int*) &_dc_and_los, los); + const region_sz_t los = static_cast(live_obj_size()); + const region_sz_t old = Atomic::cmpxchg(dc_claimed | los, &_dc_and_los, los); return old == los; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/parallel/psScavenge.cpp --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -95,7 +95,7 @@ template void do_oop_work(T* p) { assert (!oopDesc::is_null(*p), "expected non-null ref"); - assert ((oopDesc::load_decode_heap_oop_not_null(p))->is_oop(), + assert (oopDesc::is_oop(oopDesc::load_decode_heap_oop_not_null(p)), "expected an oop while scanning weak refs"); // Weak refs may be visited more than once. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/serial/defNewGeneration.inline.hpp --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -41,7 +41,7 @@ // as a weak reference. assert (!oopDesc::is_null(*p), "expected non-null ref"); oop obj = oopDesc::load_decode_heap_oop_not_null(p); - assert (obj->is_oop(), "expected an oop while scanning weak refs"); + assert (oopDesc::is_oop(obj), "expected an oop while scanning weak refs"); } #endif // ASSERT @@ -74,7 +74,7 @@ // as a weak reference. assert (!oopDesc::is_null(*p), "expected non-null ref"); oop obj = oopDesc::load_decode_heap_oop_not_null(p); - assert (obj->is_oop(), "expected an oop while scanning weak refs"); + assert (oopDesc::is_oop(obj), "expected an oop while scanning weak refs"); } #endif // ASSERT diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp --- a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, 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 @@ -343,7 +343,7 @@ oop o = oop(start); assert(!Universe::is_fully_initialized() || _sp->is_free_block(start) || - o->is_oop_or_null(), "Bad object was found"); + oopDesc::is_oop_or_null(o), "Bad object was found"); next_index++; last_p = p; last_start = start; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/collectedHeap.cpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -350,7 +350,7 @@ assert(is_in(old_obj), "Not in allocated heap"); assert(!can_elide_initializing_store_barrier(old_obj), "Else should have been filtered in new_store_pre_barrier()"); - assert(old_obj->is_oop(true), "Not an oop"); + assert(oopDesc::is_oop(old_obj, true), "Not an oop"); assert(deferred.word_size() == (size_t)(old_obj->size()), "Mismatch: multiple objects?"); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/referenceProcessor.cpp --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -401,7 +401,7 @@ void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) { _discovered_addr = java_lang_ref_Reference::discovered_addr(_ref); oop discovered = java_lang_ref_Reference::discovered(_ref); - assert(_discovered_addr && discovered->is_oop_or_null(), + assert(_discovered_addr && oopDesc::is_oop_or_null(discovered), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); _next = discovered; _referent_addr = java_lang_ref_Reference::referent_addr(_ref); @@ -409,15 +409,15 @@ assert(Universe::heap()->is_in_reserved_or_null(_referent), "Wrong oop found in java.lang.Reference object"); assert(allow_null_referent ? - _referent->is_oop_or_null() - : _referent->is_oop(), + oopDesc::is_oop_or_null(_referent) + : oopDesc::is_oop(_referent), "Expected an oop%s for referent field at " PTR_FORMAT, (allow_null_referent ? " or NULL" : ""), p2i(_referent)); } void DiscoveredListIterator::remove() { - assert(_ref->is_oop(), "Dropping a bad reference"); + assert(oopDesc::is_oop(_ref), "Dropping a bad reference"); oop_store_raw(_discovered_addr, NULL); // First _prev_next ref actually points into DiscoveredList (gross). @@ -534,7 +534,7 @@ oop next = java_lang_ref_Reference::next(iter.obj()); if ((iter.referent() == NULL || iter.is_referent_alive() || next != NULL)) { - assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)); + assert(oopDesc::is_oop_or_null(next), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)); // Remove Reference object from list iter.remove(); // Trace the cohorts @@ -582,7 +582,7 @@ } log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name()); - assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference"); + assert(oopDesc::is_oop(iter.obj(), UseConcMarkSweepGC), "Adding a bad reference"); iter.next(); } // Close the reachable set @@ -979,7 +979,7 @@ void ReferenceProcessor::verify_referent(oop obj) { bool da = discovery_is_atomic(); oop referent = java_lang_ref_Reference::referent(obj); - assert(da ? referent->is_oop() : referent->is_oop_or_null(), + assert(da ? oopDesc::is_oop(referent) : oopDesc::is_oop_or_null(referent), "Bad referent " INTPTR_FORMAT " found in Reference " INTPTR_FORMAT " during %satomic discovery ", p2i(referent), p2i(obj), da ? "" : "non-"); @@ -1057,7 +1057,7 @@ HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj); const oop discovered = java_lang_ref_Reference::discovered(obj); - assert(discovered->is_oop_or_null(), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); + assert(oopDesc::is_oop_or_null(discovered), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); if (discovered != NULL) { // The reference has already been discovered... log_develop_trace(gc, ref)("Already discovered reference (" INTPTR_FORMAT ": %s)", @@ -1118,7 +1118,7 @@ log_develop_trace(gc, ref)("Discovered reference (" INTPTR_FORMAT ": %s)", p2i(obj), obj->klass()->internal_name()); } - assert(obj->is_oop(), "Discovered a bad reference"); + assert(oopDesc::is_oop(obj), "Discovered a bad reference"); verify_referent(obj); return true; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/space.cpp --- a/hotspot/src/share/vm/gc/shared/space.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/space.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -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 @@ -491,7 +491,7 @@ HeapWord* obj_addr = mr.start(); \ HeapWord* t = mr.end(); \ while (obj_addr < t) { \ - assert(oop(obj_addr)->is_oop(), "Should be an oop"); \ + assert(oopDesc::is_oop(oop(obj_addr)), "Should be an oop"); \ obj_addr += oop(obj_addr)->oop_iterate_size(blk); \ } \ } @@ -584,7 +584,7 @@ last = cur; cur += oop(cur)->size(); } - assert(oop(last)->is_oop(), PTR_FORMAT " should be an object start", p2i(last)); + assert(oopDesc::is_oop(oop(last)), PTR_FORMAT " should be an object start", p2i(last)); return last; } } @@ -597,10 +597,10 @@ assert(p <= current_top, "p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT, p2i(p), p2i(current_top)); - assert(p == current_top || oop(p)->is_oop(), + assert(p == current_top || oopDesc::is_oop(oop(p)), "p (" PTR_FORMAT ") is not a block start - " "current_top: " PTR_FORMAT ", is_oop: %s", - p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop())); + p2i(p), p2i(current_top), BOOL_TO_STR(oopDesc::is_oop(oop(p)))); if (p < current_top) { return oop(p)->size(); } else { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/vmGCOperations.cpp --- a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -30,6 +30,7 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "runtime/handles.inline.hpp" @@ -111,6 +112,9 @@ void VM_GC_Operation::doit_epilogue() { assert(Thread::current()->is_Java_thread(), "just checking"); + // Clean up old interpreter OopMap entries that were replaced + // during the GC thread root traversal. + OopMapCache::cleanup_old_entries(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/gc/shared/workgroup.cpp --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -428,7 +428,7 @@ assert(t < _n_tasks, "bad task id."); uint old = _tasks[t]; if (old == 0) { - old = Atomic::cmpxchg(1, &_tasks[t], 0); + old = Atomic::cmpxchg(1u, &_tasks[t], 0u); } assert(_tasks[t] == 1, "What else?"); bool res = old != 0; @@ -442,15 +442,15 @@ } void SubTasksDone::all_tasks_completed(uint n_threads) { - jint observed = _threads_completed; - jint old; + uint observed = _threads_completed; + uint old; do { old = observed; observed = Atomic::cmpxchg(old+1, &_threads_completed, old); } while (observed != old); // If this was the last thread checking in, clear the tasks. uint adjusted_thread_count = (n_threads == 0 ? 1 : n_threads); - if (observed + 1 == (jint)adjusted_thread_count) { + if (observed + 1 == adjusted_thread_count) { clear(); } } @@ -474,8 +474,8 @@ bool SequentialSubTasksDone::is_task_claimed(uint& t) { t = _n_claimed; while (t < _n_tasks) { - jint res = Atomic::cmpxchg(t+1, &_n_claimed, t); - if (res == (jint)t) { + uint res = Atomic::cmpxchg(t+1, &_n_claimed, t); + if (res == t) { return false; } t = res; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,7 +36,7 @@ #ifdef ASSERT #define VERIFY_OOP(o_) \ if (VerifyOops) { \ - assert((oop(o_))->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \ + assert(oopDesc::is_oop_or_null(oop(o_)), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \ StubRoutines::_verify_oop_count++; \ } #else diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -208,7 +208,7 @@ IRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) - assert(obj->is_oop(), "must be a valid oop"); + assert(oopDesc::is_oop(obj), "must be a valid oop"); assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); IRT_END @@ -435,7 +435,6 @@ // assertions #ifdef ASSERT assert(h_exception.not_null(), "NULL exceptions should be handled by athrow"); - assert(h_exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError if (!(h_exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1318,8 +1318,6 @@ int vtable_index = Method::invalid_vtable_index; methodHandle selected_method; - assert(recv.is_null() || recv->is_oop(), "receiver is not an oop"); - // runtime method resolution if (check_null_and_abstract && recv.is_null()) { // check if receiver exists THROW(vmSymbols::java_lang_NullPointerException()); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/interpreter/oopMapCache.cpp --- a/hotspot/src/share/vm/interpreter/oopMapCache.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/interpreter/oopMapCache.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -37,6 +38,9 @@ friend class OopMapCache; friend class VerifyClosure; + private: + OopMapCacheEntry* _next; + protected: // Initialization void fill(const methodHandle& method, int bci); @@ -54,8 +58,9 @@ public: OopMapCacheEntry() : InterpreterOopMap() { + _next = NULL; #ifdef ASSERT - _resource_allocate_bit_mask = false; + _resource_allocate_bit_mask = false; #endif } }; @@ -263,23 +268,26 @@ // Check if map is generated correctly // (Use ?: operator to make sure all 'true' & 'false' are represented exactly the same so we can use == afterwards) - if (TraceOopMapGeneration && Verbose) tty->print("Locals (%d): ", max_locals); + Log(interpreter, oopmap) logv; + LogStream st(logv.trace()); + st.print("Locals (%d): ", max_locals); for(int i = 0; i < max_locals; i++) { bool v1 = is_oop(i) ? true : false; bool v2 = vars[i].is_reference() ? true : false; assert(v1 == v2, "locals oop mask generation error"); - if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); + st.print("%d", v1 ? 1 : 0); } + st.cr(); - if (TraceOopMapGeneration && Verbose) { tty->cr(); tty->print("Stack (%d): ", stack_top); } + st.print("Stack (%d): ", stack_top); for(int j = 0; j < stack_top; j++) { bool v1 = is_oop(max_locals + j) ? true : false; bool v2 = stack[j].is_reference() ? true : false; assert(v1 == v2, "stack oop mask generation error"); - if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); + st.print("%d", v1 ? 1 : 0); } - if (TraceOopMapGeneration && Verbose) tty->cr(); + st.cr(); return true; } @@ -373,8 +381,6 @@ // verify bit mask assert(verify_mask(vars, stack, max_locals, stack_top), "mask could not be verified"); - - } void OopMapCacheEntry::flush() { @@ -385,16 +391,6 @@ // Implementation of OopMapCache -#ifndef PRODUCT - -static long _total_memory_usage = 0; - -long OopMapCache::memory_usage() { - return _total_memory_usage; -} - -#endif - void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) { assert(_resource_allocate_bit_mask, "Should not resource allocate the _bit_mask"); @@ -435,15 +431,11 @@ ^ ((unsigned int) method->size_of_parameters() << 6); } +OopMapCacheEntry* volatile OopMapCache::_old_entries = NULL; -OopMapCache::OopMapCache() : - _mut(Mutex::leaf, "An OopMapCache lock", true) -{ - _array = NEW_C_HEAP_ARRAY(OopMapCacheEntry, _size, mtClass); - // Cannot call flush for initialization, since flush - // will check if memory should be deallocated - for(int i = 0; i < _size; i++) _array[i].initialize(); - NOT_PRODUCT(_total_memory_usage += sizeof(OopMapCache) + (sizeof(OopMapCacheEntry) * _size);) +OopMapCache::OopMapCache() { + _array = NEW_C_HEAP_ARRAY(OopMapCacheEntry*, _size, mtClass); + for(int i = 0; i < _size; i++) _array[i] = NULL; } @@ -452,112 +444,152 @@ // Deallocate oop maps that are allocated out-of-line flush(); // Deallocate array - NOT_PRODUCT(_total_memory_usage -= sizeof(OopMapCache) + (sizeof(OopMapCacheEntry) * _size);) - FREE_C_HEAP_ARRAY(OopMapCacheEntry, _array); + FREE_C_HEAP_ARRAY(OopMapCacheEntry*, _array); } OopMapCacheEntry* OopMapCache::entry_at(int i) const { - return &_array[i % _size]; + return (OopMapCacheEntry*)OrderAccess::load_ptr_acquire(&(_array[i % _size])); +} + +bool OopMapCache::put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old) { + return Atomic::cmpxchg_ptr (entry, &_array[i % _size], old) == old; } void OopMapCache::flush() { - for (int i = 0; i < _size; i++) _array[i].flush(); + for (int i = 0; i < _size; i++) { + OopMapCacheEntry* entry = _array[i]; + if (entry != NULL) { + _array[i] = NULL; // no barrier, only called in OopMapCache destructor + entry->flush(); + FREE_C_HEAP_OBJ(entry); + } + } } void OopMapCache::flush_obsolete_entries() { - for (int i = 0; i < _size; i++) - if (!_array[i].is_empty() && _array[i].method()->is_old()) { + assert(SafepointSynchronize::is_at_safepoint(), "called by RedefineClasses in a safepoint"); + for (int i = 0; i < _size; i++) { + OopMapCacheEntry* entry = _array[i]; + if (entry != NULL && !entry->is_empty() && entry->method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want // to pin it down so flush the entry. if (log_is_enabled(Debug, redefine, class, oopmap)) { ResourceMark rm; - log_debug(redefine, class, oopmap) + log_debug(redefine, class, interpreter, oopmap) ("flush: %s(%s): cached entry @%d", - _array[i].method()->name()->as_C_string(), _array[i].method()->signature()->as_C_string(), i); + entry->method()->name()->as_C_string(), entry->method()->signature()->as_C_string(), i); } - _array[i].flush(); + _array[i] = NULL; + entry->flush(); + FREE_C_HEAP_OBJ(entry); } + } } +// Called by GC for thread root scan during a safepoint only. The other interpreted frame oopmaps +// are generated locally and not cached. void OopMapCache::lookup(const methodHandle& method, int bci, - InterpreterOopMap* entry_for) const { - MutexLocker x(&_mut); + InterpreterOopMap* entry_for) { + assert(SafepointSynchronize::is_at_safepoint(), "called by GC in a safepoint"); + int probe = hash_value_for(method, bci); + int i; + OopMapCacheEntry* entry = NULL; - OopMapCacheEntry* entry = NULL; - int probe = hash_value_for(method, bci); + if (log_is_enabled(Debug, interpreter, oopmap)) { + static int count = 0; + ResourceMark rm; + log_debug(interpreter, oopmap) + ("%d - Computing oopmap at bci %d for %s at hash %d", ++count, bci, + method()->name_and_sig_as_C_string(), probe); + } // Search hashtable for match - int i; for(i = 0; i < _probe_depth; i++) { entry = entry_at(probe + i); - if (entry->match(method, bci)) { + if (entry != NULL && !entry->is_empty() && entry->match(method, bci)) { entry_for->resource_copy(entry); assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); + log_debug(interpreter, oopmap)("- found at hash %d", probe + i); return; } } - if (TraceOopMapGeneration) { - static int count = 0; - ResourceMark rm; - tty->print("%d - Computing oopmap at bci %d for ", ++count, bci); - method->print_value(); tty->cr(); - } + // Entry is not in hashtable. + // Compute entry - // Entry is not in hashtable. - // Compute entry and return it + OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); + tmp->initialize(); + tmp->fill(method, bci); + entry_for->resource_copy(tmp); if (method->should_not_be_cached()) { // It is either not safe or not a good idea to cache this Method* // at this time. We give the caller of lookup() a copy of the // interesting info via parameter entry_for, but we don't add it to // the cache. See the gory details in Method*.cpp. - compute_one_oop_map(method, bci, entry_for); + FREE_C_HEAP_OBJ(tmp); return; } // First search for an empty slot for(i = 0; i < _probe_depth; i++) { - entry = entry_at(probe + i); - if (entry->is_empty()) { - entry->fill(method, bci); - entry_for->resource_copy(entry); - assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - return; + entry = entry_at(probe + i); + if (entry == NULL) { + if (put_at(probe + i, tmp, NULL)) { + assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); + return; + } } } - if (TraceOopMapGeneration) { - ResourceMark rm; - tty->print_cr("*** collision in oopmap cache - flushing item ***"); - } + log_debug(interpreter, oopmap)("*** collision in oopmap cache - flushing item ***"); // No empty slot (uncommon case). Use (some approximation of a) LRU algorithm - //entry_at(probe + _probe_depth - 1)->flush(); - //for(i = _probe_depth - 1; i > 0; i--) { - // // Coping entry[i] = entry[i-1]; - // OopMapCacheEntry *to = entry_at(probe + i); - // OopMapCacheEntry *from = entry_at(probe + i - 1); - // to->copy(from); - // } + // where the first entry in the collision array is replaced with the new one. + OopMapCacheEntry* old = entry_at(probe + 0); + if (put_at(probe + 0, tmp, old)) { + enqueue_for_cleanup(old); + } else { + enqueue_for_cleanup(tmp); + } - assert(method->is_method(), "gaga"); + assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); + return; +} + +void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { + bool success = false; + OopMapCacheEntry* head; + do { + head = _old_entries; + entry->_next = head; + success = Atomic::cmpxchg_ptr (entry, &_old_entries, head) == head; + } while (!success); - entry = entry_at(probe + 0); - entry->fill(method, bci); - - // Copy the newly cached entry to input parameter - entry_for->resource_copy(entry); + if (log_is_enabled(Debug, interpreter, oopmap)) { + ResourceMark rm; + log_debug(interpreter, oopmap)("enqueue %s at bci %d for cleanup", + entry->method()->name_and_sig_as_C_string(), entry->bci()); + } +} - if (TraceOopMapGeneration) { - ResourceMark rm; - tty->print("Done with "); - method->print_value(); tty->cr(); +// This is called after GC threads are done and nothing is accessing the old_entries +// list, so no synchronization needed. +void OopMapCache::cleanup_old_entries() { + OopMapCacheEntry* entry = _old_entries; + _old_entries = NULL; + while (entry != NULL) { + if (log_is_enabled(Debug, interpreter, oopmap)) { + ResourceMark rm; + log_debug(interpreter, oopmap)("cleanup entry %s at bci %d", + entry->method()->name_and_sig_as_C_string(), entry->bci()); + } + OopMapCacheEntry* next = entry->_next; + entry->flush(); + FREE_C_HEAP_OBJ(entry); + entry = next; } - assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - - return; } void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, InterpreterOopMap* entry) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/interpreter/oopMapCache.hpp --- a/hotspot/src/share/vm/interpreter/oopMapCache.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/interpreter/oopMapCache.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -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 @@ -144,17 +144,19 @@ }; class OopMapCache : public CHeapObj { + static OopMapCacheEntry* volatile _old_entries; private: enum { _size = 32, // Use fixed size for now _probe_depth = 3 // probe depth in case of collisions }; - OopMapCacheEntry* _array; + OopMapCacheEntry* volatile * _array; unsigned int hash_value_for(const methodHandle& method, int bci) const; OopMapCacheEntry* entry_at(int i) const; + bool put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old); - mutable Mutex _mut; + static void enqueue_for_cleanup(OopMapCacheEntry* entry); void flush(); @@ -167,13 +169,11 @@ // Returns the oopMap for (method, bci) in parameter "entry". // Returns false if an oop map was not found. - void lookup(const methodHandle& method, int bci, InterpreterOopMap* entry) const; + void lookup(const methodHandle& method, int bci, InterpreterOopMap* entry); // Compute an oop map without updating the cache or grabbing any locks (for debugging) static void compute_one_oop_map(const methodHandle& method, int bci, InterpreterOopMap* entry); - - // Returns total no. of bytes allocated as part of OopMapCache's - static long memory_usage() PRODUCT_RETURN0; + static void cleanup_old_entries(); }; #endif // SHARE_VM_INTERPRETER_OOPMAPCACHE_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -765,7 +765,7 @@ C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method)) methodHandle method = CompilerToVM::asMethod(jvmci_method); - return CompilerOracle::should_not_inline(method) || method->dont_inline(); + return !Inline || CompilerOracle::should_not_inline(method) || method->dont_inline(); C2V_END C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/jvmci/jvmciRuntime.cpp --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -239,7 +239,6 @@ } #ifdef ASSERT assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); - assert(exception->is_oop(), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); @@ -385,7 +384,6 @@ } #endif Handle h_obj(thread, obj); - assert(h_obj()->is_oop(), "must be NULL or an object"); if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); @@ -407,7 +405,7 @@ EXCEPTION_MARK; #ifdef DEBUG - if (!obj->is_oop()) { + if (!oopDesc::is_oop(obj)) { ResetNoHandleMark rhm; nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); if (method != NULL) { @@ -455,8 +453,8 @@ if (obj == NULL) { tty->print("NULL"); - } else if (obj->is_oop_or_null(true) && (!as_string || !java_lang_String::is_instance(obj))) { - if (obj->is_oop_or_null(true)) { + } else if (oopDesc::is_oop_or_null(obj, true) && (!as_string || !java_lang_String::is_instance(obj))) { + if (oopDesc::is_oop_or_null(obj, true)) { char buf[O_BUFLEN]; tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); } else { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/logging/logTag.hpp --- a/hotspot/src/share/vm/logging/logTag.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/logging/logTag.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -74,6 +74,7 @@ LOG_TAG(iklass) \ LOG_TAG(init) \ LOG_TAG(inlining) \ + LOG_TAG(interpreter) \ LOG_TAG(itables) \ LOG_TAG(jit) \ LOG_TAG(jni) \ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/memory/metaspaceShared.cpp --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1613,6 +1613,8 @@ tty->print_cr("Dumping objects to open archive heap region ..."); _open_archive_heap_regions = new GrowableArray(2); MetaspaceShared::dump_open_archive_heap_objects(_open_archive_heap_regions); + + MetaspaceShared::destroy_archive_object_cache(); } G1HeapVerifier::verify_archive_regions(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/memory/metaspaceShared.hpp --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/virtualspace.hpp" +#include "oops/oop.inline.hpp" #include "utilities/exceptions.hpp" #include "utilities/macros.hpp" #include "utilities/resourceHash.hpp" @@ -96,11 +97,16 @@ return p1 == p2; } static unsigned obj_hash(oop const& p) { - unsigned hash = (unsigned)((uintptr_t)&p); - return hash ^ (hash >> LogMinObjAlignment); + assert(!p->mark()->has_bias_pattern(), + "this object should never have been locked"); // so identity_hash won't safepoin + unsigned hash = (unsigned)p->identity_hash(); + return hash; } typedef ResourceHashtable ArchivedObjectCache; + MetaspaceShared::obj_hash, + MetaspaceShared::obj_equals, + 15889, // prime number + ResourceObj::C_HEAP> ArchivedObjectCache; static ArchivedObjectCache* _archive_object_cache; public: @@ -115,7 +121,10 @@ NOT_CDS_JAVA_HEAP(return false;) } static void create_archive_object_cache() { - CDS_JAVA_HEAP_ONLY(_archive_object_cache = new ArchivedObjectCache();); + CDS_JAVA_HEAP_ONLY(_archive_object_cache = new (ResourceObj::C_HEAP, mtClass)ArchivedObjectCache();); + } + static void destroy_archive_object_cache() { + CDS_JAVA_HEAP_ONLY(delete _archive_object_cache; _archive_object_cache = NULL;); } static void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/memory/virtualspace.cpp --- a/hotspot/src/share/vm/memory/virtualspace.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/memory/virtualspace.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -582,7 +582,7 @@ assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], "area must be distinguishable from marks for mark-sweep"); - if (base() > 0) { + if (base() != NULL) { MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/metaprogramming/isRegisteredEnum.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/metaprogramming/isRegisteredEnum.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,42 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP +#define SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP + +#include "memory/allocation.hpp" +#include "metaprogramming/integralConstant.hpp" + +// Recognize registered enum types. +// Registration is by specializing this trait. +// +// This is a manual stand-in for the C++11 std::is_enum type trait. +// It's a lot of work to implement is_enum portably in C++98, so this +// manual approach is being taken for those enum types we need to +// distinguish. +template +struct IsRegisteredEnum : public FalseType {}; + +#endif // SHARE_VM_METAPROGRAMMING_ISREGISTEREDENUM_HPP + diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/metaprogramming/primitiveConversions.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/metaprogramming/primitiveConversions.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,170 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP +#define SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP + +#include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/isFloatingPoint.hpp" +#include "metaprogramming/isIntegral.hpp" +#include "metaprogramming/isRegisteredEnum.hpp" +#include "utilities/debug.hpp" + +class PrimitiveConversions : public AllStatic { +public: + // Return a value of type T with the same representation as x. + // + // T and U must be of the same size. + // + // At least one of T or U must be an integral type. The other must + // be an integral, floating point, or pointer type. + template static T cast(U x); + + // Support thin wrappers over primitive types. + // If derived from TrueType, provides representational conversion + // from T to some other type. When true, must provide + // - Value: typedef for T. + // - Decayed: typedef for decayed type. + // - static Decayed decay(T x): return value of type Decayed with + // the same representation as x. + // - static T recover(Decayed x): return a value of type T with the + // same representation as x. + template struct Translate : public FalseType {}; + +private: + + template + struct Cast; + + template static T cast_using_union(U x); +}; + +// Return an object of type T with the same value representation as x. +// +// T and U must be of the same size. It is expected that one of T and +// U is an integral type, and the other is an integral type, a +// (registered) enum type, or a floating point type +// +// This implementation uses the "union trick", which seems to be the +// best of a bad set of options. Though technically undefined +// behavior, it is widely and well supported, producing good code. In +// some cases, such as gcc, that support is explicitly documented. +// +// Using memcpy is the correct method, but some compilers produce +// wretched code for that method, even at maximal optimization levels. +// +// Using static_cast is only possible for integral and enum types, not +// for floating point types. And for integral and enum conversions, +// static_cast has unspecified or implementation-defined behavior for +// some cases. C++11 can be used to avoid most or all +// of those unspecified or implementation-defined issues, though that +// may require multi-step conversions. +// +// Using reinterpret_cast of references has undefined behavior for +// many cases, and there is much less empirical basis for its use, as +// compared to the union trick. +template +inline T PrimitiveConversions::cast_using_union(U x) { + STATIC_ASSERT(sizeof(T) == sizeof(U)); + union { T t; U u; }; + u = x; + return t; +} + +////////////////////////////////////////////////////////////////////////////// +// cast(x) +// +// Cast + +// Give an informative error if the sizes differ. +template +struct PrimitiveConversions::Cast VALUE_OBJ_CLASS_SPEC { + STATIC_ASSERT(sizeof(T) == sizeof(U)); +}; + +// Conversion between integral types. +template +struct PrimitiveConversions::Cast< + T, U, true, + typename EnableIf::value && IsIntegral::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert an enum or floating point value to an integer value. +template +struct PrimitiveConversions::Cast< + T, U, true, + typename EnableIf::value && + (IsRegisteredEnum::value || + IsFloatingPoint::value)>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert an integer to an enum or floating point value. +template +struct PrimitiveConversions::Cast< + T, U, true, + typename EnableIf::value && + (IsRegisteredEnum::value || + IsFloatingPoint::value)>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U x) const { return cast_using_union(x); } +}; + +// Convert a pointer to an integral value. +template +struct PrimitiveConversions::Cast< + T, U*, true, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(U* x) const { return reinterpret_cast(x); } +}; + +// Convert an integral value to a pointer. +template +struct PrimitiveConversions::Cast< + T*, U, true, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T* operator()(U x) const { return reinterpret_cast(x); } +}; + +template +inline T PrimitiveConversions::cast(U x) { + return Cast()(x); +} + +#endif // SHARE_VM_METAPROGRAMMING_PRIMITIVECONVERSIONS_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/constantPool.cpp --- a/hotspot/src/share/vm/oops/constantPool.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/constantPool.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -134,7 +134,7 @@ } objArrayOop ConstantPool::resolved_references() const { - return (objArrayOop)JNIHandles::resolve(_cache->resolved_references()); + return (objArrayOop)_cache->resolved_references(); } // Create resolved_references array and mapping array for original cp indexes diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/constantPool.hpp --- a/hotspot/src/share/vm/oops/constantPool.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/constantPool.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -28,6 +28,7 @@ #include "oops/arrayOop.hpp" #include "oops/cpCache.hpp" #include "oops/objArrayOop.hpp" +#include "oops/oopHandle.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/handles.hpp" @@ -821,7 +822,7 @@ private: - void set_resolved_references(jobject s) { _cache->set_resolved_references(s); } + void set_resolved_references(OopHandle s) { _cache->set_resolved_references(s); } Array* reference_map() const { return (_cache == NULL) ? NULL : _cache->reference_map(); } void set_reference_map(Array* o) { _cache->set_reference_map(o); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/cpCache.hpp --- a/hotspot/src/share/vm/oops/cpCache.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/cpCache.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -28,6 +28,7 @@ #include "interpreter/bytecodes.hpp" #include "memory/allocation.hpp" #include "oops/array.hpp" +#include "oops/oopHandle.hpp" #include "runtime/orderAccess.hpp" #include "utilities/align.hpp" @@ -413,7 +414,7 @@ // stored in the ConstantPool, which is read-only. // Array of resolved objects from the constant pool and map from resolved // object index to original constant pool index - jobject _resolved_references; + OopHandle _resolved_references; Array* _reference_map; // The narrowOop pointer to the archived resolved_references. Set at CDS dump // time when caching java heap object is supported. @@ -455,8 +456,8 @@ oop archived_references() NOT_CDS_JAVA_HEAP_RETURN_(NULL); void set_archived_references(oop o) NOT_CDS_JAVA_HEAP_RETURN; - jobject resolved_references() { return _resolved_references; } - void set_resolved_references(jobject s) { _resolved_references = s; } + oop resolved_references() { return _resolved_references.resolve(); } + void set_resolved_references(OopHandle s) { _resolved_references = s; } Array* reference_map() const { return _reference_map; } void set_reference_map(Array* o) { _reference_map = o; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -3207,7 +3207,7 @@ protected: template void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - if (!obj->is_oop_or_null()) { + if (!oopDesc::is_oop_or_null(obj)) { tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj)); Universe::print_on(tty); guarantee(false, "boom"); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/instanceRefKlass.cpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -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 @@ -72,12 +72,12 @@ // Verify referent field oop referent = java_lang_ref_Reference::referent(obj); if (referent != NULL) { - guarantee(referent->is_oop(), "referent field heap failed"); + guarantee(oopDesc::is_oop(referent), "referent field heap failed"); } // Verify next field oop next = java_lang_ref_Reference::next(obj); if (next != NULL) { - guarantee(next->is_oop(), "next field should be an oop"); + guarantee(oopDesc::is_oop(next), "next field should be an oop"); guarantee(next->is_instance(), "next field should be an instance"); guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed"); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/klass.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -713,12 +713,12 @@ } if (java_mirror() != NULL) { - guarantee(java_mirror()->is_oop(), "should be instance"); + guarantee(oopDesc::is_oop(java_mirror()), "should be instance"); } } void Klass::oop_verify_on(oop obj, outputStream* st) { - guarantee(obj->is_oop(), "should be oop"); + guarantee(oopDesc::is_oop(obj), "should be oop"); guarantee(obj->klass()->is_klass(), "klass field is not a klass"); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/method.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -214,26 +214,14 @@ } void Method::mask_for(int bci, InterpreterOopMap* mask) { - - Thread* myThread = Thread::current(); - methodHandle h_this(myThread, this); -#if defined(ASSERT) && !INCLUDE_JVMCI - bool has_capability = myThread->is_VM_thread() || - myThread->is_ConcurrentGC_thread() || - myThread->is_GC_task_thread(); - - if (!has_capability) { - if (!VerifyStack && !VerifyLastFrame) { - // verify stack calls this outside VM thread - warning("oopmap should only be accessed by the " - "VM, GC task or CMS threads (or during debugging)"); - InterpreterOopMap local_mask; - method_holder()->mask_for(h_this, bci, &local_mask); - local_mask.print(); - } + methodHandle h_this(Thread::current(), this); + // Only GC uses the OopMapCache during thread stack root scanning + // any other uses generate an oopmap but do not save it in the cache. + if (Universe::heap()->is_gc_active()) { + method_holder()->mask_for(h_this, bci, mask); + } else { + OopMapCache::compute_one_oop_map(h_this, bci, mask); } -#endif - method_holder()->mask_for(h_this, bci, mask); return; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/objArrayKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -498,6 +498,6 @@ guarantee(obj->is_objArray(), "must be objArray"); objArrayOop oa = objArrayOop(obj); for(int index = 0; index < oa->length(); index++) { - guarantee(oa->obj_at(index)->is_oop_or_null(), "should be oop"); + guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop"); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/oop.cpp --- a/hotspot/src/share/vm/oops/oop.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/oop.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -121,11 +121,44 @@ } } +// used only for asserts and guarantees +bool oopDesc::is_oop(oop obj, bool ignore_mark_word) { + if (!check_obj_alignment(obj)) return false; + if (!Universe::heap()->is_in_reserved(obj)) return false; + // obj is aligned and accessible in heap + if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false; + + // Header verification: the mark is typically non-NULL. If we're + // at a safepoint, it must not be null. + // Outside of a safepoint, the header could be changing (for example, + // another thread could be inflating a lock on this object). + if (ignore_mark_word) { + return true; + } + if (obj->mark() != NULL) { + return true; + } + return !SafepointSynchronize::is_at_safepoint(); +} + +// used only for asserts and guarantees +bool oopDesc::is_oop_or_null(oop obj, bool ignore_mark_word) { + return obj == NULL ? true : is_oop(obj, ignore_mark_word); +} + +#ifndef PRODUCT +// used only for asserts +bool oopDesc::is_unlocked_oop() const { + if (!Universe::heap()->is_in_reserved(this)) return false; + return mark()->is_unlocked(); +} +#endif // PRODUCT + VerifyOopClosure VerifyOopClosure::verify_oop; template void VerifyOopClosure::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - guarantee(obj->is_oop_or_null(), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj)); + guarantee(oopDesc::is_oop_or_null(obj), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj)); } void VerifyOopClosure::do_oop(oop* p) { VerifyOopClosure::do_oop_work(p); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/oop.hpp --- a/hotspot/src/share/vm/oops/oop.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/oop.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -287,9 +287,9 @@ inline bool is_unlocked() const; inline bool has_bias_pattern() const; - // asserts - inline bool is_oop(bool ignore_mark_word = false) const; - inline bool is_oop_or_null(bool ignore_mark_word = false) const; + // asserts and guarantees + static bool is_oop(oop obj, bool ignore_mark_word = false); + static bool is_oop_or_null(oop obj, bool ignore_mark_word = false); #ifndef PRODUCT inline bool is_unlocked_oop() const; #endif diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -94,7 +94,7 @@ } markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) { - return (markOop) Atomic::cmpxchg_ptr(new_mark, &_mark, old_mark); + return Atomic::cmpxchg(new_mark, &_mark, old_mark); } void oopDesc::init_mark() { @@ -408,14 +408,14 @@ narrowOop val = encode_heap_oop(exchange_value); narrowOop cmp = encode_heap_oop(compare_value); - narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp); + narrowOop old = Atomic::cmpxchg(val, (narrowOop*)dest, cmp); // decode old from T to oop return decode_heap_oop(old); } else { if (prebarrier) { update_barrier_set_pre((oop*)dest, exchange_value); } - return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value); + return Atomic::cmpxchg(exchange_value, (oop*)dest, compare_value); } } @@ -533,41 +533,6 @@ return mark()->has_bias_pattern(); } -// used only for asserts -bool oopDesc::is_oop(bool ignore_mark_word) const { - oop obj = (oop) this; - if (!check_obj_alignment(obj)) return false; - if (!Universe::heap()->is_in_reserved(obj)) return false; - // obj is aligned and accessible in heap - if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false; - - // Header verification: the mark is typically non-NULL. If we're - // at a safepoint, it must not be null. - // Outside of a safepoint, the header could be changing (for example, - // another thread could be inflating a lock on this object). - if (ignore_mark_word) { - return true; - } - if (mark() != NULL) { - return true; - } - return !SafepointSynchronize::is_at_safepoint(); -} - - -// used only for asserts -bool oopDesc::is_oop_or_null(bool ignore_mark_word) const { - return this == NULL ? true : is_oop(ignore_mark_word); -} - -#ifndef PRODUCT -// used only for asserts -bool oopDesc::is_unlocked_oop() const { - if (!Universe::heap()->is_in_reserved(this)) return false; - return mark()->is_unlocked(); -} -#endif // PRODUCT - // Used only for markSweep, scavenging bool oopDesc::is_gc_marked() const { return mark()->is_marked(); @@ -619,7 +584,7 @@ assert(sizeof(markOop) == sizeof(intptr_t), "CAS below requires this."); while (!oldMark->is_marked()) { - curMark = (markOop)Atomic::cmpxchg_ptr(forwardPtrMark, &_mark, oldMark); + curMark = Atomic::cmpxchg(forwardPtrMark, &_mark, oldMark); assert(is_forwarded(), "object should have been forwarded"); if (curMark == oldMark) { return NULL; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/oopHandle.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/oops/oopHandle.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -0,0 +1,51 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_OOPS_OOPHANDLE_HPP +#define SHARE_VM_OOPS_OOPHANDLE_HPP + +#include "oops/oop.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" + +// Simple class for encapsulating oop pointers stored in metadata. +// These are different from Handle. The Handle class stores pointers +// to oops on the stack, and manages the allocation from a thread local +// area in the constructor. +// This assumes that the caller will allocate the handle in the appropriate +// area. The reason for the encapsulation is to help with naming and to allow +// future uses for read barriers. + +class OopHandle { +private: + oop* _obj; + +public: + OopHandle() : _obj(NULL) {} + OopHandle(oop* w) : _obj(w) {} + + oop resolve() const { return (_obj == NULL) ? (oop)NULL : *_obj; } +}; + +#endif // SHARE_VM_OOPS_OOPHANDLE_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/oopsHierarchy.hpp --- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -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 @@ -25,6 +25,8 @@ #ifndef SHARE_VM_OOPS_OOPSHIERARCHY_HPP #define SHARE_VM_OOPS_OOPSHIERARCHY_HPP +#include "metaprogramming/integralConstant.hpp" +#include "metaprogramming/primitiveConversions.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" @@ -142,6 +144,15 @@ operator oop* () const { return (oop *)obj(); } }; +template<> +struct PrimitiveConversions::Translate : public TrueType { + typedef oop Value; + typedef oopDesc* Decayed; + + static Decayed decay(Value x) { return x.obj(); } + static Value recover(Decayed x) { return oop(x); } +}; + #define DEF_OOP(type) \ class type##OopDesc; \ class type##Oop : public oop { \ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/oops/symbol.cpp --- a/hotspot/src/share/vm/oops/symbol.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/oops/symbol.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -219,7 +219,7 @@ void Symbol::decrement_refcount() { if (_refcount >= 0) { // not a permanent symbol - jshort new_value = Atomic::add(-1, &_refcount); + short new_value = Atomic::add(short(-1), &_refcount); #ifdef ASSERT if (new_value == -1) { // we have transitioned from 0 -> -1 print(); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/opto/c2compiler.cpp --- a/hotspot/src/share/vm/opto/c2compiler.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/opto/c2compiler.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -283,7 +283,7 @@ case vmIntrinsics::_weakCompareAndSetIntAcquire: case vmIntrinsics::_weakCompareAndSetIntRelease: case vmIntrinsics::_weakCompareAndSetInt: - if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapI)) return false; break; /* CompareAndSet, Byte: */ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/opto/lcm.cpp --- a/hotspot/src/share/vm/opto/lcm.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/opto/lcm.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -39,7 +39,7 @@ // Check whether val is not-null-decoded compressed oop, // i.e. will grab into the base of the heap if it represents NULL. static bool accesses_heap_base_zone(Node *val) { - if (Universe::narrow_oop_base() > 0) { // Implies UseCompressedOops. + if (Universe::narrow_oop_base() != NULL) { // Implies UseCompressedOops. if (val && val->is_Mach()) { if (val->as_Mach()->ideal_Opcode() == Op_DecodeN) { // This assumes all Decodes with TypePtr::NotNull are matched to nodes that diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/opto/loopPredicate.cpp --- a/hotspot/src/share/vm/opto/loopPredicate.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -912,7 +912,7 @@ Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); Node* rng = cmp->in(2); - assert(rng->Opcode() == Op_LoadRange || _igvn.type(rng)->is_int() >= 0, "must be"); + assert(rng->Opcode() == Op_LoadRange || iff->is_RangeCheck() || _igvn.type(rng)->is_int()->_lo >= 0, "must be"); assert(invar.is_invariant(rng), "range must be invariant"); int scale = 1; Node* offset = zero; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/opto/runtime.cpp --- a/hotspot/src/share/vm/opto/runtime.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/opto/runtime.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, 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 @@ -1563,7 +1563,7 @@ JRT_ENTRY_NO_ASYNC(void, OptoRuntime::register_finalizer(oopDesc* obj, JavaThread* thread)) - assert(obj->is_oop(), "must be a valid oop"); + assert(oopDesc::is_oop(obj), "must be a valid oop"); assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); JRT_END diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jni.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -4028,7 +4028,7 @@ } _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { - jint result = 0; + jint result = JNI_ERR; // On Windows, let CreateJavaVM run with SEH protection #ifdef _WIN32 __try { @@ -4063,7 +4063,7 @@ DT_RETURN_MARK_DECL(DestroyJavaVM, jint , HOTSPOT_JNI_DESTROYJAVAVM_RETURN(_ret_ref)); -jint JNICALL jni_DestroyJavaVM(JavaVM *vm) { +static jint JNICALL jni_DestroyJavaVM_inner(JavaVM *vm) { HOTSPOT_JNI_DESTROYJAVAVM_ENTRY(vm); jint res = JNI_ERR; DT_RETURN_MARK(DestroyJavaVM, jint, (const jint&)res); @@ -4099,6 +4099,20 @@ } } +jint JNICALL jni_DestroyJavaVM(JavaVM *vm) { + jint result = JNI_ERR; + // On Windows, we need SEH protection +#ifdef _WIN32 + __try { +#endif + result = jni_DestroyJavaVM_inner(vm); +#ifdef _WIN32 + } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { + // Nothing to do. + } +#endif + return result; +} static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool daemon) { JavaVMAttachArgs *args = (JavaVMAttachArgs *) _args; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvm.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -326,8 +326,8 @@ } arrayOop s = arrayOop(JNIHandles::resolve_non_null(src)); arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst)); - assert(s->is_oop(), "JVM_ArrayCopy: src not an oop"); - assert(d->is_oop(), "JVM_ArrayCopy: dst not an oop"); + assert(oopDesc::is_oop(s), "JVM_ArrayCopy: src not an oop"); + assert(oopDesc::is_oop(d), "JVM_ArrayCopy: dst not an oop"); // Do copy s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread); JVM_END diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvmti.xml --- a/hotspot/src/share/vm/prims/jvmti.xml Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvmti.xml Tue Sep 05 10:09:44 2017 -0700 @@ -227,7 +227,8 @@ label CDATA #REQUIRED> - + @@ -438,7 +439,7 @@ The details of how this is initiated are implementation specific. - + A native JVMTI Agent may be statically linked with the VM. The manner in which the library and VM image are combined is @@ -6647,7 +6648,7 @@ If is not a module object. - If is not a module object. + If is not a module object. If the package @@ -6702,7 +6703,7 @@ If is not a module object. - If is not a module object. + If is not a module object. If the package @@ -13786,7 +13787,7 @@ - + The callbacks used for events. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvmti.xsl --- a/hotspot/src/share/vm/prims/jvmti.xsl Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvmti.xsl Tue Sep 05 10:09:44 2017 -0700 @@ -905,8 +905,15 @@ - - + + + + + + + + + @@ -922,7 +929,7 @@ - + diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvmtiEnvBase.cpp --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1490,14 +1490,14 @@ } } -GrowableArray* JvmtiModuleClosure::_tbl = NULL; +GrowableArray* JvmtiModuleClosure::_tbl = NULL; jvmtiError JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr) { ResourceMark rm; MutexLocker ml(Module_lock); - _tbl = new GrowableArray(77); + _tbl = new GrowableArray(77); if (_tbl == NULL) { return JVMTI_ERROR_OUT_OF_MEMORY; } @@ -1513,7 +1513,7 @@ return JVMTI_ERROR_OUT_OF_MEMORY; } for (jint idx = 0; idx < len; idx++) { - array[idx] = _tbl->at(idx); + array[idx] = JNIHandles::make_local(Thread::current(), _tbl->at(idx).resolve()); } _tbl = NULL; *modules_ptr = array; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvmtiEnvBase.hpp --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -30,6 +30,7 @@ #include "prims/jvmtiEventController.hpp" #include "prims/jvmtiThreadState.hpp" #include "prims/jvmtiThreadState.inline.hpp" +#include "oops/oopHandle.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/frame.hpp" #include "runtime/handles.inline.hpp" @@ -704,12 +705,12 @@ // Jvmti module closure to collect all modules loaded to the system. class JvmtiModuleClosure : public StackObj { private: - static GrowableArray *_tbl; // Protected with Module_lock + static GrowableArray *_tbl; // Protected with Module_lock static void do_module(ModuleEntry* entry) { assert_locked_or_safepoint(Module_lock); - jobject module = entry->module_handle(); - guarantee(module != NULL, "module object is NULL"); + OopHandle module = entry->module_handle(); + guarantee(module.resolve() != NULL, "module object is NULL"); _tbl->push(module); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/jvmtiExport.cpp --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -764,7 +764,7 @@ ModuleEntry* module_entry = InstanceKlass::cast(klass)->module(); assert(module_entry != NULL, "module_entry should always be set"); if (module_entry->is_named() && - module_entry->module_handle() != NULL && + module_entry->module() != NULL && !module_entry->has_default_read_edges()) { if (!module_entry->set_has_default_read_edges()) { // We won a potential race. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/prims/privilegedStack.cpp --- a/hotspot/src/share/vm/prims/privilegedStack.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/prims/privilegedStack.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -39,8 +39,8 @@ #endif // CHECK_UNHANDLED_OOPS _frame_id = vfst->frame_id(); _next = next; - assert(_privileged_context == NULL || _privileged_context->is_oop(), "must be an oop"); - assert(protection_domain() == NULL || protection_domain()->is_oop(), "must be an oop"); + assert(oopDesc::is_oop_or_null(_privileged_context), "must be an oop"); + assert(oopDesc::is_oop_or_null(protection_domain()), "must be an oop"); } void PrivilegedElement::oops_do(OopClosure* f) { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/atomic.hpp --- a/hotspot/src/share/vm/runtime/atomic.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/atomic.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -26,6 +26,14 @@ #define SHARE_VM_RUNTIME_ATOMIC_HPP #include "memory/allocation.hpp" +#include "metaprogramming/conditional.hpp" +#include "metaprogramming/enableIf.hpp" +#include "metaprogramming/isIntegral.hpp" +#include "metaprogramming/isPointer.hpp" +#include "metaprogramming/isSame.hpp" +#include "metaprogramming/primitiveConversions.hpp" +#include "metaprogramming/removeCV.hpp" +#include "metaprogramming/removePointer.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -77,11 +85,17 @@ // Atomically add to a location. Returns updated value. add*() provide: // add-value-to-dest - inline static jshort add (jshort add_value, volatile jshort* dest); - inline static jint add (jint add_value, volatile jint* dest); - inline static size_t add (size_t add_value, volatile size_t* dest); - inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest); - inline static void* add_ptr(intptr_t add_value, volatile void* dest); + + template + inline static D add(I add_value, D volatile* dest); + + inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest) { + return add(add_value, dest); + } + + inline static void* add_ptr(intptr_t add_value, volatile void* dest) { + return add(add_value, reinterpret_cast(dest)); + } // Atomically increment location. inc*() provide: // increment-dest @@ -111,13 +125,216 @@ // *dest with exchange_value if the comparison succeeded. Returns prior // value of *dest. cmpxchg*() provide: // compare-and-exchange - inline static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order = memory_order_conservative); - // See comment above about using jlong atomics on 32-bit platforms - inline static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static unsigned int cmpxchg (unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value, cmpxchg_memory_order order = memory_order_conservative); - inline static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value, cmpxchg_memory_order order = memory_order_conservative); + + template + inline static D cmpxchg(T exchange_value, + D volatile* dest, + U compare_value, + cmpxchg_memory_order order = memory_order_conservative); + + // Performs atomic compare of *dest and NULL, and replaces *dest + // with exchange_value if the comparison succeeded. Returns true if + // the comparison succeeded and the exchange occurred. This is + // often used as part of lazy initialization, as a lock-free + // alternative to the Double-Checked Locking Pattern. + template + inline static bool replace_if_null(T* value, D* volatile* dest, + cmpxchg_memory_order order = memory_order_conservative); + + inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, + volatile intptr_t* dest, + intptr_t compare_value, + cmpxchg_memory_order order = memory_order_conservative) { + return cmpxchg(exchange_value, dest, compare_value, order); + } + + inline static void* cmpxchg_ptr(void* exchange_value, + volatile void* dest, + void* compare_value, + cmpxchg_memory_order order = memory_order_conservative) { + return cmpxchg(exchange_value, + reinterpret_cast(dest), + compare_value, + order); + } + +private: + // Test whether From is implicitly convertible to To. + // From and To must be pointer types. + // Note: Provides the limited subset of C++11 std::is_convertible + // that is needed here. + template struct IsPointerConvertible; + + // Dispatch handler for add. Provides type-based validity checking + // and limited conversions around calls to the platform-specific + // implementation layer provided by PlatformAdd. + template + struct AddImpl; + + // Platform-specific implementation of add. Support for sizes of 4 + // bytes and (if different) pointer size bytes are required. The + // class is a function object that must be default constructable, + // with these requirements: + // + // - dest is of type D*, an integral or pointer type. + // - add_value is of type I, an integral type. + // - sizeof(I) == sizeof(D). + // - if D is an integral type, I == D. + // - platform_add is an object of type PlatformAdd. + // + // Then + // platform_add(add_value, dest) + // must be a valid expression, returning a result convertible to D. + // + // No definition is provided; all platforms must explicitly define + // this class and any needed specializations. + template struct PlatformAdd; + + // Helper base classes for defining PlatformAdd. To use, define + // PlatformAdd or a specialization that derives from one of these, + // and include in the PlatformAdd definition the support function + // (described below) required by the base class. + // + // These classes implement the required function object protocol for + // PlatformAdd, using a support function template provided by the + // derived class. Let add_value (of type I) and dest (of type D) be + // the arguments the object is called with. If D is a pointer type + // P*, then let addend (of type I) be add_value * sizeof(P); + // otherwise, addend is add_value. + // + // FetchAndAdd requires the derived class to provide + // fetch_and_add(addend, dest) + // atomically adding addend to the value of dest, and returning the + // old value. + // + // AddAndFetch requires the derived class to provide + // add_and_fetch(addend, dest) + // atomically adding addend to the value of dest, and returning the + // new value. + // + // When D is a pointer type P*, both fetch_and_add and add_and_fetch + // treat it as if it were a uintptr_t; they do not perform any + // scaling of the addend, as that has already been done by the + // caller. +public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. + template struct FetchAndAdd; + template struct AddAndFetch; +private: + + // Support for platforms that implement some variants of add using a + // (typically out of line) non-template helper function. The + // generic arguments passed to PlatformAdd need to be translated to + // the appropriate type for the helper function, the helper function + // invoked on the translated arguments, and the result translated + // back. Type is the parameter / return type of the helper + // function. No scaling of add_value is performed when D is a pointer + // type, so this function can be used to implement the support function + // required by AddAndFetch. + template + static D add_using_helper(Fn fn, I add_value, D volatile* dest); + + // Dispatch handler for cmpxchg. Provides type-based validity + // checking and limited conversions around calls to the + // platform-specific implementation layer provided by + // PlatformCmpxchg. + template + struct CmpxchgImpl; + + // Platform-specific implementation of cmpxchg. Support for sizes + // of 1, 4, and 8 are required. The class is a function object that + // must be default constructable, with these requirements: + // + // - dest is of type T*. + // - exchange_value and compare_value are of type T. + // - order is of type cmpxchg_memory_order. + // - platform_cmpxchg is an object of type PlatformCmpxchg. + // + // Then + // platform_cmpxchg(exchange_value, dest, compare_value, order) + // must be a valid expression, returning a result convertible to T. + // + // A default definition is provided, which declares a function template + // T operator()(T, T volatile*, T, cmpxchg_memory_order) const + // + // For each required size, a platform must either provide an + // appropriate definition of that function, or must entirely + // specialize the class template for that size. + template struct PlatformCmpxchg; + + // Support for platforms that implement some variants of cmpxchg + // using a (typically out of line) non-template helper function. + // The generic arguments passed to PlatformCmpxchg need to be + // translated to the appropriate type for the helper function, the + // helper invoked on the translated arguments, and the result + // translated back. Type is the parameter / return type of the + // helper function. + template + static T cmpxchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest, + T compare_value); + + // Support platforms that do not provide Read-Modify-Write + // byte-level atomic access. To use, derive PlatformCmpxchg<1> from + // this class. +public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. + struct CmpxchgByteUsingInt; +private: +}; + +template +struct Atomic::IsPointerConvertible : AllStatic { + // Determine whether From* is implicitly convertible to To*, using + // the "sizeof trick". + typedef char yes; + typedef char (&no)[2]; + + static yes test(To*); + static no test(...); + static From* test_value; + + static const bool value = (sizeof(yes) == sizeof(test(test_value))); +}; + +// Define FetchAndAdd and AddAndFetch helper classes before including +// platform file, which may use these as base classes, requiring they +// be complete. + +template +struct Atomic::FetchAndAdd VALUE_OBJ_CLASS_SPEC { + template + D operator()(I add_value, D volatile* dest) const; +}; + +template +struct Atomic::AddAndFetch VALUE_OBJ_CLASS_SPEC { + template + D operator()(I add_value, D volatile* dest) const; +}; + +// Define the class before including platform file, which may specialize +// the operator definition. No generic definition of specializations +// of the operator template are provided, nor are there any generic +// specializations of the class. The platform file is responsible for +// providing those. +template +struct Atomic::PlatformCmpxchg VALUE_OBJ_CLASS_SPEC { + template + T operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const; +}; + +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. The definition is later +// in this file, near the other definitions related to cmpxchg. +struct Atomic::CmpxchgByteUsingInt VALUE_OBJ_CLASS_SPEC { + template + T operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const; }; // platform specific in-line definitions - must come before shared definitions @@ -131,8 +348,93 @@ #error size_t is not WORD_SIZE, interesting platform, but missing implementation here #endif -inline size_t Atomic::add(size_t add_value, volatile size_t* dest) { - return (size_t) add_ptr((intptr_t) add_value, (volatile intptr_t*) dest); +template +inline D Atomic::add(I add_value, D volatile* dest) { + return AddImpl()(add_value, dest); +} + +template +struct Atomic::AddImpl< + I, D, + typename EnableIf::value && + IsIntegral::value && + (sizeof(I) <= sizeof(D)) && + (IsSigned::value == IsSigned::value)>::type> + VALUE_OBJ_CLASS_SPEC +{ + D operator()(I add_value, D volatile* dest) const { + D addend = add_value; + return PlatformAdd()(addend, dest); + } +}; + +template +struct Atomic::AddImpl< + I, P*, + typename EnableIf::value && (sizeof(I) <= sizeof(P*))>::type> + VALUE_OBJ_CLASS_SPEC +{ + P* operator()(I add_value, P* volatile* dest) const { + STATIC_ASSERT(sizeof(intptr_t) == sizeof(P*)); + STATIC_ASSERT(sizeof(uintptr_t) == sizeof(P*)); + typedef typename Conditional::value, + intptr_t, + uintptr_t>::type CI; + CI addend = add_value; + return PlatformAdd()(addend, dest); + } +}; + +// Most platforms do not support atomic add on a 2-byte value. However, +// if the value occupies the most significant 16 bits of an aligned 32-bit +// word, then we can do this with an atomic add of (add_value << 16) +// to the 32-bit word. +// +// The least significant parts of this 32-bit word will never be affected, even +// in case of overflow/underflow. +// +// Use the ATOMIC_SHORT_PAIR macro (see macros.hpp) to get the desired alignment. +template<> +struct Atomic::AddImpl VALUE_OBJ_CLASS_SPEC { + jshort operator()(jshort add_value, jshort volatile* dest) const { +#ifdef VM_LITTLE_ENDIAN + assert((intx(dest) & 0x03) == 0x02, "wrong alignment"); + jint new_value = Atomic::add(add_value << 16, (volatile jint*)(dest-1)); +#else + assert((intx(dest) & 0x03) == 0x00, "wrong alignment"); + jint new_value = Atomic::add(add_value << 16, (volatile jint*)(dest)); +#endif + return (jshort)(new_value >> 16); // preserves sign + } +}; + +template +template +inline D Atomic::FetchAndAdd::operator()(I add_value, D volatile* dest) const { + I addend = add_value; + // If D is a pointer type P*, scale by sizeof(P). + if (IsPointer::value) { + addend *= sizeof(typename RemovePointer::type); + } + D old = static_cast(this)->fetch_and_add(addend, dest); + return old + add_value; +} + +template +template +inline D Atomic::AddAndFetch::operator()(I add_value, D volatile* dest) const { + // If D is a pointer type P*, scale by sizeof(P). + if (IsPointer::value) { + add_value *= sizeof(typename RemovePointer::type); + } + return static_cast(this)->add_and_fetch(add_value, dest); +} + +template +inline D Atomic::add_using_helper(Fn fn, I add_value, D volatile* dest) { + return PrimitiveConversions::cast( + fn(PrimitiveConversions::cast(add_value), + reinterpret_cast(dest))); } inline void Atomic::inc(volatile size_t* dest) { @@ -143,87 +445,158 @@ dec_ptr((volatile intptr_t*) dest); } -#ifndef VM_HAS_SPECIALIZED_CMPXCHG_BYTE -/* - * This is the default implementation of byte-sized cmpxchg. It emulates jbyte-sized cmpxchg - * in terms of jint-sized cmpxchg. Platforms may override this by defining their own inline definition - * as well as defining VM_HAS_SPECIALIZED_CMPXCHG_BYTE. This will cause the platform specific - * implementation to be used instead. - */ -inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, - jbyte compare_value, cmpxchg_memory_order order) { - STATIC_ASSERT(sizeof(jbyte) == 1); - volatile jint* dest_int = - reinterpret_cast(align_down(dest, sizeof(jint))); - size_t offset = pointer_delta(dest, dest_int, 1); - jint cur = *dest_int; - jbyte* cur_as_bytes = reinterpret_cast(&cur); +template +inline D Atomic::cmpxchg(T exchange_value, + D volatile* dest, + U compare_value, + cmpxchg_memory_order order) { + return CmpxchgImpl()(exchange_value, dest, compare_value, order); +} + +template +inline bool Atomic::replace_if_null(T* value, D* volatile* dest, + cmpxchg_memory_order order) { + // Presently using a trivial implementation in terms of cmpxchg. + // Consider adding platform support, to permit the use of compiler + // intrinsics like gcc's __sync_bool_compare_and_swap. + D* expected_null = NULL; + return expected_null == cmpxchg(value, dest, expected_null, order); +} + +// Handle cmpxchg for integral and enum types. +// +// All the involved types must be identical. +template +struct Atomic::CmpxchgImpl< + T, T, T, + typename EnableIf::value || IsRegisteredEnum::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest, T compare_value, + cmpxchg_memory_order order) const { + // Forward to the platform handler for the size of T. + return PlatformCmpxchg()(exchange_value, + dest, + compare_value, + order); + } +}; + +// Handle cmpxchg for pointer types. +// +// The destination's type and the compare_value type must be the same, +// ignoring cv-qualifiers; we don't care about the cv-qualifiers of +// the compare_value. +// +// The exchange_value must be implicitly convertible to the +// destination's type; it must be type-correct to store the +// exchange_value in the destination. +template +struct Atomic::CmpxchgImpl< + T*, D*, U*, + typename EnableIf::value && + IsSame::type, + typename RemoveCV::type>::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + D* operator()(T* exchange_value, D* volatile* dest, U* compare_value, + cmpxchg_memory_order order) const { + // Allow derived to base conversion, and adding cv-qualifiers. + D* new_value = exchange_value; + // Don't care what the CV qualifiers for compare_value are, + // but we need to match D* when calling platform support. + D* old_value = const_cast(compare_value); + return PlatformCmpxchg()(new_value, dest, old_value, order); + } +}; + +// Handle cmpxchg for types that have a translator. +// +// All the involved types must be identical. +// +// This translates the original call into a call on the decayed +// arguments, and returns the recovered result of that translated +// call. +template +struct Atomic::CmpxchgImpl< + T, T, T, + typename EnableIf::value>::type> + VALUE_OBJ_CLASS_SPEC +{ + T operator()(T exchange_value, T volatile* dest, T compare_value, + cmpxchg_memory_order order) const { + typedef PrimitiveConversions::Translate Translator; + typedef typename Translator::Decayed Decayed; + STATIC_ASSERT(sizeof(T) == sizeof(Decayed)); + return Translator::recover( + cmpxchg(Translator::decay(exchange_value), + reinterpret_cast(dest), + Translator::decay(compare_value), + order)); + } +}; + +template +inline T Atomic::cmpxchg_using_helper(Fn fn, + T exchange_value, + T volatile* dest, + T compare_value) { + STATIC_ASSERT(sizeof(Type) == sizeof(T)); + return PrimitiveConversions::cast( + fn(PrimitiveConversions::cast(exchange_value), + reinterpret_cast(dest), + PrimitiveConversions::cast(compare_value))); +} + +template +inline T Atomic::CmpxchgByteUsingInt::operator()(T exchange_value, + T volatile* dest, + T compare_value, + cmpxchg_memory_order order) const { + STATIC_ASSERT(sizeof(T) == sizeof(uint8_t)); + uint8_t canon_exchange_value = exchange_value; + uint8_t canon_compare_value = compare_value; + volatile uint32_t* aligned_dest + = reinterpret_cast(align_down(dest, sizeof(uint32_t))); + size_t offset = pointer_delta(dest, aligned_dest, 1); + uint32_t cur = *aligned_dest; + uint8_t* cur_as_bytes = reinterpret_cast(&cur); // current value may not be what we are looking for, so force it // to that value so the initial cmpxchg will fail if it is different - cur_as_bytes[offset] = compare_value; + cur_as_bytes[offset] = canon_compare_value; // always execute a real cmpxchg so that we get the required memory // barriers even on initial failure do { // value to swap in matches current value ... - jint new_value = cur; + uint32_t new_value = cur; // ... except for the one jbyte we want to update - reinterpret_cast(&new_value)[offset] = exchange_value; + reinterpret_cast(&new_value)[offset] = canon_exchange_value; - jint res = cmpxchg(new_value, dest_int, cur, order); - if (res == cur) break; // success + uint32_t res = cmpxchg(new_value, aligned_dest, cur, order); + if (res == cur) break; // success - // at least one jbyte in the jint changed value, so update - // our view of the current jint + // at least one byte in the int changed value, so update + // our view of the current int cur = res; - // if our jbyte is still as cur we loop and try again - } while (cur_as_bytes[offset] == compare_value); + // if our byte is still as cur we loop and try again + } while (cur_as_bytes[offset] == canon_compare_value); - return cur_as_bytes[offset]; + return PrimitiveConversions::cast(cur_as_bytes[offset]); } -#endif // VM_HAS_SPECIALIZED_CMPXCHG_BYTE - inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) { assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest); } -inline unsigned Atomic::cmpxchg(unsigned int exchange_value, - volatile unsigned int* dest, unsigned int compare_value, - cmpxchg_memory_order order) { - assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); - return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest, - (jint)compare_value, order); -} - -inline jshort Atomic::add(jshort add_value, volatile jshort* dest) { - // Most platforms do not support atomic add on a 2-byte value. However, - // if the value occupies the most significant 16 bits of an aligned 32-bit - // word, then we can do this with an atomic add of (add_value << 16) - // to the 32-bit word. - // - // The least significant parts of this 32-bit word will never be affected, even - // in case of overflow/underflow. - // - // Use the ATOMIC_SHORT_PAIR macro (see macros.hpp) to get the desired alignment. -#ifdef VM_LITTLE_ENDIAN - assert((intx(dest) & 0x03) == 0x02, "wrong alignment"); - jint new_value = Atomic::add(add_value << 16, (volatile jint*)(dest-1)); -#else - assert((intx(dest) & 0x03) == 0x00, "wrong alignment"); - jint new_value = Atomic::add(add_value << 16, (volatile jint*)(dest)); -#endif - return (jshort)(new_value >> 16); // preserves sign -} - inline void Atomic::inc(volatile jshort* dest) { - (void)add(1, dest); + (void)add(jshort(1), dest); } inline void Atomic::dec(volatile jshort* dest) { - (void)add(-1, dest); + (void)add(jshort(-1), dest); } #endif // SHARE_VM_RUNTIME_ATOMIC_HPP diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -217,7 +217,7 @@ // Reallocation may trigger GC. If deoptimization happened on return from // call which returns oop we need to save it since it is not in oopmap. oop result = deoptee.saved_oop_result(&map); - assert(result == NULL || result->is_oop(), "must be oop"); + assert(oopDesc::is_oop_or_null(result), "must be oop"); return_value = Handle(thread, result); assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); if (TraceDeoptimization) { @@ -1373,6 +1373,30 @@ } +#if INCLUDE_JVMCI +address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* cm) { + // there is no exception handler for this pc => deoptimize + cm->make_not_entrant(); + + // Use Deoptimization::deoptimize for all of its side-effects: + // revoking biases of monitors, gathering traps statistics, logging... + // it also patches the return pc but we do not care about that + // since we return a continuation to the deopt_blob below. + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, UseBiasedLocking); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + assert(caller_frame.cb()->as_nmethod_or_null() == cm, "expect top frame nmethod"); + Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); + + MethodData* trap_mdo = get_method_data(thread, cm->method(), true); + if (trap_mdo != NULL) { + trap_mdo->inc_trap_count(Deoptimization::Reason_not_compiled_exception_handler); + } + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); +} +#endif void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/deoptimization.hpp --- a/hotspot/src/share/vm/runtime/deoptimization.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -136,6 +136,10 @@ static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map); static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason); +#if INCLUDE_JVMCI + static address deoptimize_for_missing_exception_handler(CompiledMethod* cm); +#endif + private: // Does the actual work for deoptimizing a single frame static void deoptimize_single_frame(JavaThread* thread, frame fr, DeoptReason reason); diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/globals.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -715,9 +715,6 @@ product(bool, PrintVMQWaitTime, false, \ "Print out the waiting time in VM operation queue") \ \ - develop(bool, TraceOopMapGeneration, false, \ - "Show OopMapGeneration") \ - \ product(bool, MethodFlushing, true, \ "Reclamation of zombie and not-entrant methods") \ \ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/handles.cpp --- a/hotspot/src/share/vm/runtime/handles.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/handles.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -34,7 +34,7 @@ oop* HandleArea::allocate_handle(oop obj) { assert(_handle_mark_nesting > 1, "memory leak: allocating handle outside HandleMark"); assert(_no_handle_mark_nesting == 0, "allocating handle inside NoHandleMark"); - assert(obj->is_oop(), "not an oop: " INTPTR_FORMAT, p2i(obj)); + assert(oopDesc::is_oop(obj), "not an oop: " INTPTR_FORMAT, p2i(obj)); return real_allocate_handle(obj); } #endif @@ -99,7 +99,7 @@ while (bottom < top) { // This test can be moved up but for now check every oop. - assert((*bottom)->is_oop(), "handle should point to oop"); + assert(oopDesc::is_oop(*bottom), "handle should point to oop"); f->do_oop(bottom++); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/javaCalls.cpp --- a/hotspot/src/share/vm/runtime/javaCalls.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -567,7 +567,7 @@ "Bad JNI oop argument %d: " PTR_FORMAT, _pos, v); // Verify the pointee. oop vv = resolve_indirect_oop(v, _value_state[_pos]); - guarantee(vv->is_oop_or_null(true), + guarantee(oopDesc::is_oop_or_null(vv, true), "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT, _pos, v, p2i(vv)); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/memprofiler.cpp --- a/hotspot/src/share/vm/runtime/memprofiler.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/memprofiler.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -129,7 +129,7 @@ fprintf(_log_fp, UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",%6ld\n", handles_memory_usage / K, resource_memory_usage / K, - OopMapCache::memory_usage() / K); + 0L); fflush(_log_fp); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/os.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -755,9 +755,9 @@ // Make updating the random seed thread safe. while (true) { unsigned int seed = _rand_seed; - int rand = random_helper(seed); + unsigned int rand = random_helper(seed); if (Atomic::cmpxchg(rand, &_rand_seed, seed) == seed) { - return rand; + return static_cast(rand); } } } @@ -988,7 +988,7 @@ // See if we were just given an oop directly if (p != NULL && Universe::heap()->block_is_obj(p)) { print = true; - } else if (p == NULL && ((oopDesc*)addr)->is_oop()) { + } else if (p == NULL && oopDesc::is_oop(oop(addr))) { p = (HeapWord*) addr; print = true; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/safepoint.cpp --- a/hotspot/src/share/vm/runtime/safepoint.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/safepoint.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1104,7 +1104,7 @@ // the other registers. In order to preserve it over GCs we need // to keep it in a handle. oop result = caller_fr.saved_oop_result(&map); - assert(result == NULL || result->is_oop(), "must be oop"); + assert(oopDesc::is_oop_or_null(result), "must be oop"); return_value = Handle(thread(), result); assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -209,7 +209,7 @@ assert(false, "should be optimized out"); return; } - assert(orig->is_oop(true /* ignore mark word */), "Error"); + assert(oopDesc::is_oop(orig, true /* ignore mark word */), "Error"); // store the original value that was in the field reference thread->satb_mark_queue().enqueue(orig); JRT_END @@ -585,7 +585,7 @@ int args_size = ArgumentSizeComputer(sig).size() + 1; assert(args_size <= caller.interpreter_frame_expression_stack_size(), "receiver must be on interpreter stack"); oop result = cast_to_oop(*caller.interpreter_frame_tos_at(args_size - 1)); - assert(Universe::heap()->is_in(result) && result->is_oop(), "receiver must be an oop"); + assert(Universe::heap()->is_in(result) && oopDesc::is_oop(result), "receiver must be an oop"); return result; } @@ -638,20 +638,7 @@ if (t != NULL) { return cm->code_begin() + t->pco(); } else { - // there is no exception handler for this pc => deoptimize - cm->make_not_entrant(); - - // Use Deoptimization::deoptimize for all of its side-effects: - // revoking biases of monitors, gathering traps statistics, logging... - // it also patches the return pc but we do not care about that - // since we return a continuation to the deopt_blob below. - JavaThread* thread = JavaThread::current(); - RegisterMap reg_map(thread, UseBiasedLocking); - frame runtime_frame = thread->last_frame(); - frame caller_frame = runtime_frame.sender(®_map); - Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); - - return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + return Deoptimization::deoptimize_for_missing_exception_handler(cm); } } #endif // INCLUDE_JVMCI @@ -997,7 +984,7 @@ return; } #endif // INCLUDE_JVMCI - assert(obj->is_oop(), "must be a valid oop"); + assert(oopDesc::is_oop(obj), "must be a valid oop"); assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); JRT_END @@ -1165,8 +1152,6 @@ } } - assert(receiver.is_null() || receiver->is_oop(), "wrong receiver"); - // Resolve method if (attached_method.not_null()) { // Parameterized by attached method. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/synchronizer.cpp --- a/hotspot/src/share/vm/runtime/synchronizer.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -1407,7 +1407,6 @@ assert(inf->header()->is_neutral(), "invariant"); assert(inf->object() == object, "invariant"); assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid"); - event.cancel(); // let's not post an inflation event, unless we did the deed ourselves return inf; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/thread.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -2514,6 +2514,9 @@ address low_addr = stack_end(); size_t len = stack_guard_zone_size(); + assert(is_aligned(low_addr, os::vm_page_size()), "Stack base should be the start of a page"); + assert(is_aligned(len, os::vm_page_size()), "Stack size should be a multiple of page size"); + int must_commit = os::must_commit_stack_guard_pages(); // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); @@ -3187,7 +3190,7 @@ oop obj = oopDesc::load_decode_heap_oop(p); if (obj == NULL) return; tty->print(INTPTR_FORMAT ": ", p2i(p)); - if (obj->is_oop_or_null()) { + if (oopDesc::is_oop_or_null(obj)) { if (obj->is_objArray()) { tty->print_cr("valid objArray: " INTPTR_FORMAT, p2i(obj)); } else { diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/vframe.cpp --- a/hotspot/src/share/vm/runtime/vframe.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/vframe.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -396,14 +396,7 @@ StackValueCollection* interpretedVFrame::stack_data(bool expressions) const { InterpreterOopMap oop_mask; - // oopmap for current bci - if ((TraceDeoptimization && Verbose) JVMCI_ONLY( || PrintDeoptimizationDetails)) { - methodHandle m_h(Thread::current(), method()); - OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); - } else { - method()->mask_for(bci(), &oop_mask); - } - + method()->mask_for(bci(), &oop_mask); const int mask_len = oop_mask.number_of_entries(); // If the method is native, method()->max_locals() is not telling the truth. diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -83,6 +83,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" +#include "oops/oopHandle.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.hpp" @@ -235,7 +236,7 @@ nonstatic_field(ConstantPool, _operands, Array*) \ nonstatic_field(ConstantPool, _resolved_klasses, Array*) \ nonstatic_field(ConstantPool, _length, int) \ - nonstatic_field(ConstantPoolCache, _resolved_references, jobject) \ + nonstatic_field(ConstantPoolCache, _resolved_references, OopHandle) \ nonstatic_field(ConstantPoolCache, _reference_map, Array*) \ nonstatic_field(ConstantPoolCache, _length, int) \ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ @@ -1438,6 +1439,7 @@ declare_oop_type(oop) \ declare_oop_type(narrowOop) \ declare_oop_type(typeArrayOop) \ + declare_oop_type(OopHandle) \ \ /*************************************/ \ /* MethodOop-related data structures */ \ diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/runtime/vmStructs.hpp --- a/hotspot/src/share/vm/runtime/vmStructs.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, 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 @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_VMSTRUCTS_HPP #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/services/heapDumper.cpp --- a/hotspot/src/share/vm/services/heapDumper.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/services/heapDumper.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -764,7 +764,7 @@ // reflection and Unsafe classes may have a reference to a // Klass* so filter it out. - assert(o->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(o)); + assert(oopDesc::is_oop_or_null(o), "Expected an oop or NULL at " PTR_FORMAT, p2i(o)); writer->write_objectID(o); break; } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/services/mallocTracker.hpp --- a/hotspot/src/share/vm/services/mallocTracker.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/services/mallocTracker.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -53,7 +53,7 @@ } inline void allocate(size_t sz) { - Atomic::add(1, &_count); + Atomic::inc(&_count); if (sz > 0) { Atomic::add(sz, &_size); DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size)); @@ -64,7 +64,7 @@ inline void deallocate(size_t sz) { assert(_count > 0, "Nothing allocated yet"); assert(_size >= sz, "deallocation > allocated"); - Atomic::add(-1, &_count); + Atomic::dec(&_count); if (sz > 0) { // unary minus operator applied to unsigned type, result still unsigned #pragma warning(suppress: 4146) @@ -74,7 +74,7 @@ inline void resize(long sz) { if (sz != 0) { - Atomic::add(sz, &_size); + Atomic::add(size_t(sz), &_size); DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);) } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/services/memTracker.hpp --- a/hotspot/src/share/vm/services/memTracker.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/services/memTracker.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -213,6 +213,7 @@ if (tracking_level() < NMT_summary) return; VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag, true); + VirtualMemoryTracker::add_committed_region((address)addr, size, stack); } } diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/shark/sharkRuntime.cpp --- a/hotspot/src/share/vm/shark/sharkRuntime.cpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/shark/sharkRuntime.cpp Tue Sep 05 10:09:44 2017 -0700 @@ -136,7 +136,7 @@ JRT_ENTRY(void, SharkRuntime::register_finalizer(JavaThread* thread, oop object)) - assert(object->is_oop(), "should be"); + assert(oopDesc::is_oop(object), "should be"); assert(object->klass()->has_finalizer(), "should have"); InstanceKlass::register_finalizer(instanceOop(object), CHECK); JRT_END diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/trace/traceDataTypes.hpp --- a/hotspot/src/share/vm/trace/traceDataTypes.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/trace/traceDataTypes.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, 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 @@ -28,6 +28,7 @@ #include #include "utilities/globalDefinitions.hpp" +#include "utilities/ticks.hpp" enum { CONTENT_TYPE_NONE = 0, @@ -54,10 +55,11 @@ NUM_RESERVED_EVENTS = JVM_CONTENT_TYPES_END }; -typedef enum ReservedEvent ReservedEvent; - typedef u8 traceid; +class ClassLoaderData; +class Klass; +class Method; class ModuleEntry; class PackageEntry; class Symbol; diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/trace/traceEvent.hpp --- a/hotspot/src/share/vm/trace/traceEvent.hpp Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/trace/traceEvent.hpp Tue Sep 05 10:09:44 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, 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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_TRACE_TRACEEVENT_HPP #define SHARE_VM_TRACE_TRACEEVENT_HPP +#include "trace/traceTime.hpp" #include "utilities/macros.hpp" enum EventStartTime { @@ -34,25 +35,18 @@ #if INCLUDE_TRACE #include "trace/traceBackend.hpp" -#include "trace/tracing.hpp" #include "tracefiles/traceEventIds.hpp" -#include "tracefiles/traceTypes.hpp" #include "utilities/ticks.hpp" template -class TraceEvent : public StackObj { +class TraceEvent { private: bool _started; -#ifdef ASSERT - bool _committed; - bool _cancelled; - protected: - bool _ignore_check; -#endif protected: jlong _startTime; jlong _endTime; + DEBUG_ONLY(bool _committed;) void set_starttime(const TracingTime& time) { _startTime = time; @@ -67,10 +61,7 @@ _endTime(0), _started(false) #ifdef ASSERT - , - _committed(false), - _cancelled(false), - _ignore_check(false) + , _committed(false) #endif { if (T::is_enabled()) { @@ -100,10 +91,9 @@ void commit() { if (!should_commit()) { - DEBUG_ONLY(cancel()); return; } - assert(!_cancelled, "Committing an event that has already been cancelled"); + assert(!_committed, "event already committed"); if (_startTime == 0) { static_cast(this)->set_starttime(Tracing::time()); } else if (_endTime == 0) { @@ -111,8 +101,8 @@ } if (static_cast(this)->should_write()) { static_cast(this)->writeEvent(); + DEBUG_ONLY(_committed = true;) } - DEBUG_ONLY(set_commited()); } static TraceEventId id() { @@ -134,32 +124,6 @@ static bool has_stacktrace() { return T::hasStackTrace; } - - void cancel() { - assert(!_committed && !_cancelled, - "event was already committed/cancelled"); - DEBUG_ONLY(_cancelled = true); - } - - ~TraceEvent() { - if (_started) { - assert(_ignore_check || _committed || _cancelled, - "event was not committed/cancelled"); - } - } - -#ifdef ASSERT - protected: - void ignoreCheck() { - _ignore_check = true; - } - - private: - void set_commited() { - assert(!_committed, "event has already been committed"); - _committed = true; - } -#endif // ASSERT }; #endif // INCLUDE_TRACE diff -r 898607275d6e -r 5b4ba31ce49b hotspot/src/share/vm/trace/traceEventClasses.xsl --- a/hotspot/src/share/vm/trace/traceEventClasses.xsl Sun Sep 03 19:31:11 2017 +0530 +++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl Tue Sep 05 10:09:44 2017 -0700 @@ -1,6 +1,6 @@