# HG changeset patch # User herrick # Date 1555675242 14400 # Node ID 4649818834e0815ee51f9c554b08e5f0d28f84c6 # Parent 221a589c52eec7ed45c111a8069b3a290126d761# Parent 79e95d8dd85dd42350e53cc43aee4df3dc288740 Merge diff -r 221a589c52ee -r 4649818834e0 .hgtags --- a/.hgtags Fri Apr 19 07:55:28 2019 -0400 +++ b/.hgtags Fri Apr 19 08:00:42 2019 -0400 @@ -554,3 +554,4 @@ 46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14 f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15 9d0ae9508d5337b0dc7cc4684be42888c4023755 jdk-13+16 +93b702d2a0cb9e32160208f6700aede1f8492773 jdk-13+17 diff -r 221a589c52ee -r 4649818834e0 doc/testing.html --- a/doc/testing.html Fri Apr 19 07:55:28 2019 -0400 +++ b/doc/testing.html Fri Apr 19 08:00:42 2019 -0400 @@ -41,6 +41,7 @@
  • Notes for Specific Tests
  • @@ -194,5 +195,9 @@
    $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker"

    To run these tests correctly, additional parameters for the correct docker image are required on Ubuntu 18.04 by using JAVA_OPTIONS.

    $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" JTREG="JAVA_OPTIONS=-Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest"
    +

    Non-US locale

    +

    If your locale is non-US, some tests are likely to fail. To work around this you can set the locale to US. On Unix platforms simply setting LANG="en_US" in the environment before running tests should work. On Windows, setting JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US" helps for most, but not all test cases. For example:

    +
    $ export LANG="en_US" && make test TEST=...
    +$ make test JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US" TEST=...
    diff -r 221a589c52ee -r 4649818834e0 doc/testing.md --- a/doc/testing.md Fri Apr 19 07:55:28 2019 -0400 +++ b/doc/testing.md Fri Apr 19 08:00:42 2019 -0400 @@ -388,6 +388,17 @@ $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" JTREG="JAVA_OPTIONS=-Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest" +### Non-US locale + +If your locale is non-US, some tests are likely to fail. To work around this you can +set the locale to US. On Unix platforms simply setting `LANG="en_US"` in the +environment before running tests should work. On Windows, setting +`JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US"` helps for most, but not all test cases. +For example: + + $ export LANG="en_US" && make test TEST=... + $ make test JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US" TEST=... + --- # Override some definitions in the global css file that are not optimal for # this document. diff -r 221a589c52ee -r 4649818834e0 make/autoconf/jdk-version.m4 --- a/make/autoconf/jdk-version.m4 Fri Apr 19 07:55:28 2019 -0400 +++ b/make/autoconf/jdk-version.m4 Fri Apr 19 08:00:42 2019 -0400 @@ -66,7 +66,33 @@ AC_SUBST(PRODUCT_SUFFIX) AC_SUBST(JDK_RC_PLATFORM_NAME) AC_SUBST(HOTSPOT_VM_DISTRO) + + # Set the MACOSX Bundle Name base + AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base], + [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names. + @<:@not specified@:>@])]) + if test "x$with_macosx_bundle_name_base" = xyes; then + AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value]) + elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then + AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base]) + elif test "x$with_macosx_bundle_name_base" != x; then + # Set MACOSX_BUNDLE_NAME_BASE to the configured value. + MACOSX_BUNDLE_NAME_BASE="$with_macosx_bundle_name_base" + fi AC_SUBST(MACOSX_BUNDLE_NAME_BASE) + + # Set the MACOSX Bundle ID base + AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base], + [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs. + @<:@not specified@:>@])]) + if test "x$with_macosx_bundle_id_base" = xyes; then + AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value]) + elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then + AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base]) + elif test "x$with_macosx_bundle_id_base" != x; then + # Set MACOSX_BUNDLE_ID_BASE to the configured value. + MACOSX_BUNDLE_ID_BASE="$with_macosx_bundle_id_base" + fi AC_SUBST(MACOSX_BUNDLE_ID_BASE) # Set the JDK RC name diff -r 221a589c52ee -r 4649818834e0 make/autoconf/libraries.m4 --- a/make/autoconf/libraries.m4 Fri Apr 19 07:55:28 2019 -0400 +++ b/make/autoconf/libraries.m4 Fri Apr 19 08:00:42 2019 -0400 @@ -130,6 +130,11 @@ BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lthread" fi + # perfstat lib + if test "x$OPENJDK_TARGET_OS" = xaix; then + BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lperfstat" + fi + if test "x$OPENJDK_TARGET_OS" = xsolaris; then BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \ -lrt -lkstat" diff -r 221a589c52ee -r 4649818834e0 make/jdk/src/classes/build/tools/classlist/HelloClasslist.java --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java Fri Apr 19 07:55:28 2019 -0400 +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,13 +67,24 @@ .forEach(System.out::println); // Common concatenation patterns - String const_I = "string" + args.length; - String const_S = "string" + String.valueOf(args.length); - String S_const = String.valueOf(args.length) + "string"; - String S_S = String.valueOf(args.length) + String.valueOf(args.length); - String const_J = "string" + System.currentTimeMillis(); - String I_const = args.length + "string"; - String J_const = System.currentTimeMillis() + "string"; + String SS = String.valueOf(args.length) + String.valueOf(args.length); + String CS = "string" + String.valueOf(args.length); + String SC = String.valueOf(args.length) + "string"; + String SCS = String.valueOf(args.length) + "string" + String.valueOf(args.length); + String CSS = "string" + String.valueOf(args.length) + String.valueOf(args.length); + String CSCS = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length); + String SCSC = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string"; + String CSCSC = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string"; + String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length); + String CI = "string" + args.length; + String IC = args.length + "string"; + String CIC = "string" + args.length + "string"; + String CICI = "string" + args.length + "string" + args.length; + String CJ = "string" + System.currentTimeMillis(); + String JC = System.currentTimeMillis() + "string"; + String CJC = "string" + System.currentTimeMillis() + "string"; + String CJCJ = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis(); + String CJCJC = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis() + "string"; String newDate = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( LocalDateTime.now(ZoneId.of("GMT"))); diff -r 221a589c52ee -r 4649818834e0 make/launcher/Launcher-java.base.gmk --- a/make/launcher/Launcher-java.base.gmk Fri Apr 19 07:55:28 2019 -0400 +++ b/make/launcher/Launcher-java.base.gmk Fri Apr 19 08:00:42 2019 -0400 @@ -39,7 +39,6 @@ # overwritten. $(eval $(call SetupBuildLauncher, java, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS -DENABLE_ARG_FILES, \ - LDFLAGS_solaris := -R$(OPENWIN_HOME)/lib$(OPENJDK_TARGET_CPU_ISADIR), \ EXTRA_RC_FLAGS := $(JAVA_RC_FLAGS), \ VERSION_INFO_RESOURCE := $(JAVA_VERSION_INFO_RESOURCE), \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/java_objs, \ diff -r 221a589c52ee -r 4649818834e0 make/launcher/LauncherCommon.gmk --- a/make/launcher/LauncherCommon.gmk Fri Apr 19 07:55:28 2019 -0400 +++ b/make/launcher/LauncherCommon.gmk Fri Apr 19 08:00:42 2019 -0400 @@ -73,8 +73,7 @@ # compile time defines exceeding Visual Studio 2013 limitations. # CFLAGS Additional CFLAGS # CFLAGS_windows Additional CFLAGS_windows -# LDFLAGS_solaris Additional LDFLAGS_solaris -# RC_FLAGS Additional RC_FLAGS +# EXTRA_RC_FLAGS Additional EXTRA_RC_FLAGS # MACOSX_SIGNED On macosx, sign this binary # OPTIMIZATION Override default optimization level (LOW) # OUTPUT_DIR Override default output directory @@ -139,7 +138,7 @@ NAME := $1, \ EXTRA_FILES := $(LAUNCHER_SRC)/main.c, \ OPTIMIZATION := $$($1_OPTIMIZATION), \ - CFLAGS := $$(CFLAGS_JDKEXE) $$($1_CFLAGS) \ + CFLAGS := $$(CFLAGS_JDKEXE) \ $(LAUNCHER_CFLAGS) \ $(VERSION_CFLAGS) \ -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' \ diff -r 221a589c52ee -r 4649818834e0 src/hotspot/cpu/ppc/vm_version_ppc.cpp --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -38,6 +38,9 @@ #include "vm_version_ppc.hpp" #include +#if defined(_AIX) +#include +#endif #if defined(LINUX) && defined(VM_LITTLE_ENDIAN) #include @@ -382,6 +385,58 @@ } void VM_Version::print_platform_virtualization_info(outputStream* st) { +#if defined(_AIX) + // more info about perfstat API see + // https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.prftools/idprftools_perfstat_glob_partition.htm + int rc = 0; + perfstat_partition_total_t pinfo; + memset(&pinfo, 0, sizeof(perfstat_partition_total_t)); + rc = perfstat_partition_total(NULL, &pinfo, sizeof(perfstat_partition_total_t), 1); + if (rc != 1) { + return; + } else { + st->print_cr("Virtualization type : PowerVM"); + } + // CPU information + perfstat_cpu_total_t cpuinfo; + memset(&cpuinfo, 0, sizeof(perfstat_cpu_total_t)); + rc = perfstat_cpu_total(NULL, &cpuinfo, sizeof(perfstat_cpu_total_t), 1); + if (rc != 1) { + return; + } + + st->print_cr("Processor description : %s", cpuinfo.description); + st->print_cr("Processor speed : %llu Hz", cpuinfo.processorHZ); + + st->print_cr("LPAR partition name : %s", pinfo.name); + st->print_cr("LPAR partition number : %u", pinfo.lpar_id); + st->print_cr("LPAR partition type : %s", pinfo.type.b.shared_enabled ? "shared" : "dedicated"); + st->print_cr("LPAR mode : %s", pinfo.type.b.donate_enabled ? "donating" : pinfo.type.b.capped ? "capped" : "uncapped"); + st->print_cr("LPAR partition group ID : %u", pinfo.group_id); + st->print_cr("LPAR shared pool ID : %u", pinfo.pool_id); + + st->print_cr("AMS (active memory sharing) : %s", pinfo.type.b.ams_capable ? "capable" : "not capable"); + st->print_cr("AMS (active memory sharing) : %s", pinfo.type.b.ams_enabled ? "on" : "off"); + st->print_cr("AME (active memory expansion) : %s", pinfo.type.b.ame_enabled ? "on" : "off"); + + if (pinfo.type.b.ame_enabled) { + st->print_cr("AME true memory in bytes : %llu", pinfo.true_memory); + st->print_cr("AME expanded memory in bytes : %llu", pinfo.expanded_memory); + } + + st->print_cr("SMT : %s", pinfo.type.b.smt_capable ? "capable" : "not capable"); + st->print_cr("SMT : %s", pinfo.type.b.smt_enabled ? "on" : "off"); + int ocpus = pinfo.online_cpus > 0 ? pinfo.online_cpus : 1; + st->print_cr("LPAR threads : %d", cpuinfo.ncpus/ocpus); + st->print_cr("LPAR online virtual cpus : %d", pinfo.online_cpus); + st->print_cr("LPAR logical cpus : %d", cpuinfo.ncpus); + st->print_cr("LPAR maximum virtual cpus : %u", pinfo.max_cpus); + st->print_cr("LPAR minimum virtual cpus : %u", pinfo.min_cpus); + st->print_cr("LPAR entitled capacity : %4.2f", (double) (pinfo.entitled_proc_capacity/100.0)); + st->print_cr("LPAR online memory : %llu MB", pinfo.online_memory); + st->print_cr("LPAR maximum memory : %llu MB", pinfo.max_memory); + st->print_cr("LPAR minimum memory : %llu MB", pinfo.min_memory); +#else const char* info_file = "/proc/ppc64/lparcfg"; const char* kw[] = { "system_type=", // qemu indicates PowerKVM "partition_entitled_capacity=", // entitled processor capacity percentage @@ -400,6 +455,7 @@ if (!print_matching_lines_from_file(info_file, st, kw)) { st->print_cr(" <%s Not Available>", info_file); } +#endif } bool VM_Version::use_biased_locking() { diff -r 221a589c52ee -r 4649818834e0 src/hotspot/cpu/s390/macroAssembler_s390.cpp --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -4355,12 +4355,9 @@ // Emitter does not KILL cnt and base arguments, since they need to be copied to // work registers anyway. // Actually, only r0, r1, and r5 are killed. -unsigned int MacroAssembler::Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len) { - // Src_addr is evenReg. - // Src_len is odd_Reg. +unsigned int MacroAssembler::Clear_Array(Register cnt_arg, Register base_pointer_arg, Register odd_tmp_reg) { int block_start = offset(); - Register tmp_reg = src_len; // Holds target instr addr for EX. Register dst_len = Z_R1; // Holds dst len for MVCLE. Register dst_addr = Z_R0; // Holds dst addr for MVCLE. @@ -4369,7 +4366,7 @@ BLOCK_COMMENT("Clear_Array {"); // Check for zero len and convert to long. - z_ltgfr(src_len, cnt_arg); // Remember casted value for doSTG case. + z_ltgfr(odd_tmp_reg, cnt_arg); z_bre(done); // Nothing to do if len == 0. // Prefetch data to be cleared. @@ -4378,16 +4375,17 @@ z_pfd(0x02, 256, Z_R0, base_pointer_arg); } - z_sllg(dst_len, src_len, 3); // #bytes to clear. - z_cghi(src_len, 32); // Check for len <= 256 bytes (<=32 DW). - z_brnh(doXC); // If so, use executed XC to clear. + z_sllg(dst_len, odd_tmp_reg, 3); // #bytes to clear. + z_cghi(odd_tmp_reg, 32); // Check for len <= 256 bytes (<=32 DW). + z_brnh(doXC); // If so, use executed XC to clear. // MVCLE: initialize long arrays (general case). bind(doMVCLE); z_lgr(dst_addr, base_pointer_arg); - clear_reg(src_len, true, false); // Src len of MVCLE is zero. - - MacroAssembler::move_long_ext(dst_addr, src_addr, 0); + // Pass 0 as source length to MVCLE: destination will be filled with padding byte 0. + // The even register of the register pair is not killed. + clear_reg(odd_tmp_reg, true, false); + MacroAssembler::move_long_ext(dst_addr, as_Register(odd_tmp_reg->encoding()-1), 0); z_bru(done); // XC: initialize short arrays. @@ -4396,12 +4394,12 @@ z_xc(0,0,base_pointer_arg,0,base_pointer_arg); bind(doXC); - add2reg(dst_len, -1); // Get #bytes-1 for EXECUTE. + add2reg(dst_len, -1); // Get #bytes-1 for EXECUTE. if (VM_Version::has_ExecuteExtensions()) { - z_exrl(dst_len, XC_template); // Execute XC with var. len. + z_exrl(dst_len, XC_template); // Execute XC with var. len. } else { - z_larl(tmp_reg, XC_template); - z_ex(dst_len,0,Z_R0,tmp_reg); // Execute XC with var. len. + z_larl(odd_tmp_reg, XC_template); + z_ex(dst_len,0,Z_R0,odd_tmp_reg); // Execute XC with var. len. } // z_bru(done); // fallthru @@ -4463,7 +4461,7 @@ // Compiler ensures base is doubleword aligned and cnt is #doublewords. // Emitter does not KILL cnt and base arguments, since they need to be copied to // work registers anyway. -// Actually, only r0, r1, r4, and r5 (which are work registers) are killed. +// Actually, only r0, r1, (which are work registers) and odd_tmp_reg are killed. // // For very large arrays, exploit MVCLE H/W support. // MVCLE instruction automatically exploits H/W-optimized page mover. @@ -4471,9 +4469,7 @@ // - All full pages are cleared with the page mover H/W assist. // - Remaining bytes are again cleared by a series of XC to self. // -unsigned int MacroAssembler::Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register src_addr, Register src_len) { - // Src_addr is evenReg. - // Src_len is odd_Reg. +unsigned int MacroAssembler::Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register odd_tmp_reg) { int block_start = offset(); Register dst_len = Z_R1; // Holds dst len for MVCLE. @@ -4486,11 +4482,10 @@ // Prepare other args to MVCLE. z_lgr(dst_addr, base_pointer_arg); - // Indicate unused result. - (void) clear_reg(src_len, true, false); // Src len of MVCLE is zero. - - // Clear. - MacroAssembler::move_long_ext(dst_addr, src_addr, 0); + // Pass 0 as source length to MVCLE: destination will be filled with padding byte 0. + // The even register of the register pair is not killed. + (void) clear_reg(odd_tmp_reg, true, false); // Src len of MVCLE is zero. + MacroAssembler::move_long_ext(dst_addr, as_Register(odd_tmp_reg->encoding() - 1), 0); BLOCK_COMMENT("} Clear_Array_Const_Big"); int block_end = offset(); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/cpu/s390/macroAssembler_s390.hpp --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -828,9 +828,9 @@ //-------------------------- //--- Operations on arrays. //-------------------------- - unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len); + unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register odd_tmp_reg); unsigned int Clear_Array_Const(long cnt, Register base); - unsigned int Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register src_addr, Register src_len); + unsigned int Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register odd_tmp_reg); unsigned int CopyRawMemory_AlignedDisjoint(Register src_reg, Register dst_reg, Register cnt_reg, Register tmp1_reg, Register tmp2_reg); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/cpu/s390/s390.ad --- a/src/hotspot/cpu/s390/s390.ad Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/cpu/s390/s390.ad Fri Apr 19 08:00:42 2019 -0400 @@ -474,6 +474,19 @@ /*Z_R15_H,Z_R15*/ // SP ); +// z_long_reg without even registers +reg_class z_long_odd_reg( +/*Z_R0_H,Z_R0*/ // R0 +/*Z_R1_H,Z_R1*/ + Z_R3_H,Z_R3, + Z_R5_H,Z_R5, + Z_R7_H,Z_R7, + Z_R9_H,Z_R9, + Z_R11_H,Z_R11, + Z_R13_H,Z_R13 +/*Z_R14_H,Z_R14,*/ // return_pc +/*Z_R15_H,Z_R15*/ // SP +); // Special Class for Condition Code Flags Register @@ -3378,6 +3391,7 @@ match(RegL); match(revenRegL); match(roddRegL); + match(allRoddRegL); match(rarg1RegL); match(rarg5RegL); format %{ %} @@ -3400,6 +3414,14 @@ interface(REG_INTER); %} +// available odd registers for iRegL +operand allRoddRegL() %{ + constraint(ALLOC_IN_RC(z_long_odd_reg)); + match(iRegL); + format %{ %} + interface(REG_INTER); +%} + operand rarg1RegL() %{ constraint(ALLOC_IN_RC(z_rarg1_long_reg)); match(iRegL); @@ -9899,23 +9921,23 @@ ins_pipe(pipe_class_dummy); %} -instruct inlineCallClearArrayConstBig(immL cnt, iRegP_N2P base, Universe dummy, revenRegL srcA, roddRegL srcL, flagsReg cr) %{ +instruct inlineCallClearArrayConstBig(immL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); - effect(TEMP srcA, TEMP srcL, KILL cr); // R0, R1 are killed, too. + effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too. ins_cost(200); // TODO: s390 port size(VARIABLE_SIZE); // Variable in size due to optimized constant loader. format %{ "ClearArrayConstBig $cnt,$base" %} - ins_encode %{ __ Clear_Array_Const_Big($cnt$$constant, $base$$Register, $srcA$$Register, $srcL$$Register); %} - ins_pipe(pipe_class_dummy); -%} - -instruct inlineCallClearArray(iRegL cnt, iRegP_N2P base, Universe dummy, revenRegL srcA, roddRegL srcL, flagsReg cr) %{ + ins_encode %{ __ Clear_Array_Const_Big($cnt$$constant, $base$$Register, $tmpL$$Register); %} + ins_pipe(pipe_class_dummy); +%} + +instruct inlineCallClearArray(iRegL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); - effect(TEMP srcA, TEMP srcL, KILL cr); // R0, R1 are killed, too. + effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too. ins_cost(300); // TODO: s390 port size(FIXED_SIZE); // z/Architecture: emitted code depends on PreferLAoverADD being on/off. format %{ "ClearArrayVar $cnt,$base" %} - ins_encode %{ __ Clear_Array($cnt$$Register, $base$$Register, $srcA$$Register, $srcL$$Register); %} + ins_encode %{ __ Clear_Array($cnt$$Register, $base$$Register, $tmpL$$Register); %} ins_pipe(pipe_class_dummy); %} diff -r 221a589c52ee -r 4649818834e0 src/hotspot/cpu/x86/stubGenerator_x86_32.cpp --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -2968,9 +2968,8 @@ __ enter(); __ subptr(rsp, 8 * wordSize); - if (multi_block) { - __ push(limit); - } + handleSOERegisters(true /*saving*/); + __ movptr(buf, buf_param); __ movptr(state, state_param); if (multi_block) { @@ -2981,9 +2980,7 @@ __ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask, buf, state, ofs, limit, rsp, multi_block); - if (multi_block) { - __ pop(limit); - } + handleSOERegisters(false /*restoring*/); __ addptr(rsp, 8 * wordSize); __ leave(); __ ret(0); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/os/aix/os_aix.cpp --- a/src/hotspot/os/aix/os_aix.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/os/aix/os_aix.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -1405,13 +1405,7 @@ st->print_cr("type: %s", (wi.app_wpar ? "application" : "system")); } - // print partition info - libperfstat::partitioninfo_t pi; - if (libperfstat::get_partitioninfo(&pi)) { - st->print_cr("partition info"); - st->print_cr(" name: %s", pi.name); - } - + VM_Version::print_platform_virtualization_info(st); } void os::print_memory_info(outputStream* st) { diff -r 221a589c52ee -r 4649818834e0 src/hotspot/os/linux/osContainer_linux.cpp --- a/src/hotspot/os/linux/osContainer_linux.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/os/linux/osContainer_linux.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -122,7 +122,25 @@ char *subsystem_path() { return _path; } }; -CgroupSubsystem* memory = NULL; +class CgroupMemorySubsystem: CgroupSubsystem { + friend class OSContainer; + + private: + /* Some container runtimes set limits via cgroup + * hierarchy. If set to true consider also memory.stat + * file if everything else seems unlimited */ + bool _uses_mem_hierarchy; + + public: + CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) { + _uses_mem_hierarchy = false; + } + + bool is_hierarchical() { return _uses_mem_hierarchy; } + void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } +}; + +CgroupMemorySubsystem* memory = NULL; CgroupSubsystem* cpuset = NULL; CgroupSubsystem* cpu = NULL; CgroupSubsystem* cpuacct = NULL; @@ -131,21 +149,24 @@ PRAGMA_DIAG_PUSH PRAGMA_FORMAT_NONLITERAL_IGNORED -template int subsystem_file_contents(CgroupSubsystem* c, +template int subsystem_file_line_contents(CgroupSubsystem* c, const char *filename, + const char *matchline, const char *scan_fmt, T returnval) { FILE *fp = NULL; char *p; char file[MAXPATHLEN+1]; char buf[MAXPATHLEN+1]; + char discard[MAXPATHLEN+1]; + bool found_match = false; if (c == NULL) { - log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL"); + log_debug(os, container)("subsystem_file_line_contents: CgroupSubsytem* is NULL"); return OSCONTAINER_ERROR; } if (c->subsystem_path() == NULL) { - log_debug(os, container)("subsystem_file_contents: subsystem path is NULL"); + log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL"); return OSCONTAINER_ERROR; } @@ -160,16 +181,32 @@ log_trace(os, container)("Path to %s is %s", filename, file); fp = fopen(file, "r"); if (fp != NULL) { - p = fgets(buf, MAXPATHLEN, fp); - if (p != NULL) { - int matched = sscanf(p, scan_fmt, returnval); - if (matched == 1) { + int err = 0; + while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) { + found_match = false; + if (matchline == NULL) { + // single-line file case + int matched = sscanf(p, scan_fmt, returnval); + found_match = (matched == 1); + } else { + // multi-line file case + if (strstr(p, matchline) != NULL) { + // discard matchline string prefix + int matched = sscanf(p, scan_fmt, discard, returnval); + found_match = (matched == 2); + } else { + continue; // substring not found + } + } + if (found_match) { fclose(fp); return 0; } else { + err = 1; log_debug(os, container)("Type %s not found in file %s", scan_fmt, file); } - } else { + } + if (err == 0) { log_debug(os, container)("Empty file %s", file); } } else { @@ -186,10 +223,11 @@ return_type variable; \ { \ int err; \ - err = subsystem_file_contents(subsystem, \ - filename, \ - scan_fmt, \ - &variable); \ + err = subsystem_file_line_contents(subsystem, \ + filename, \ + NULL, \ + scan_fmt, \ + &variable); \ if (err != 0) \ return (return_type) OSCONTAINER_ERROR; \ \ @@ -201,16 +239,33 @@ char variable[bufsize]; \ { \ int err; \ - err = subsystem_file_contents(subsystem, \ - filename, \ - scan_fmt, \ - variable); \ + err = subsystem_file_line_contents(subsystem, \ + filename, \ + NULL, \ + scan_fmt, \ + variable); \ if (err != 0) \ return (return_type) NULL; \ \ log_trace(os, container)(logstring, variable); \ } +#define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename, \ + matchline, logstring, scan_fmt, variable) \ + return_type variable; \ +{ \ + int err; \ + err = subsystem_file_line_contents(subsystem, \ + filename, \ + matchline, \ + scan_fmt, \ + &variable); \ + if (err != 0) \ + return (return_type) OSCONTAINER_ERROR; \ + \ + log_trace(os, container)(logstring, variable); \ +} + /* init * * Initialize the container support and determine if @@ -266,7 +321,7 @@ } while ((token = strsep(&cptr, ",")) != NULL) { if (strcmp(token, "memory") == 0) { - memory = new CgroupSubsystem(tmproot, tmpmount); + memory = new CgroupMemorySubsystem(tmproot, tmpmount); } else if (strcmp(token, "cpuset") == 0) { cpuset = new CgroupSubsystem(tmproot, tmpmount); } else if (strcmp(token, "cpu") == 0) { @@ -344,6 +399,10 @@ while ((token = strsep(&controllers, ",")) != NULL) { if (strcmp(token, "memory") == 0) { memory->set_subsystem_path(base); + jlong hierarchy = uses_mem_hierarchy(); + if (hierarchy > 0) { + memory->set_hierarchical(true); + } } else if (strcmp(token, "cpuset") == 0) { cpuset->set_subsystem_path(base); } else if (strcmp(token, "cpu") == 0) { @@ -360,6 +419,7 @@ // command line arguments have been processed. if ((mem_limit = memory_limit_in_bytes()) > 0) { os::Linux::set_physical_memory(mem_limit); + log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit); } _is_containerized = true; @@ -374,6 +434,21 @@ } } +/* uses_mem_hierarchy + * + * Return whether or not hierarchical cgroup accounting is being + * done. + * + * return: + * A number > 0 if true, or + * OSCONTAINER_ERROR for not supported + */ +jlong OSContainer::uses_mem_hierarchy() { + GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy", + "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); + return use_hierarchy; +} + /* memory_limit_in_bytes * @@ -389,7 +464,18 @@ "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); if (memlimit >= _unlimited_memory) { - log_trace(os, container)("Memory Limit is: Unlimited"); + log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); + if (memory->is_hierarchical()) { + const char* matchline = "hierarchical_memory_limit"; + char* format = "%s " JULONG_FORMAT; + GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline, + "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit) + if (hier_memlimit >= _unlimited_memory) { + log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); + } else { + return (jlong)hier_memlimit; + } + } return (jlong)-1; } else { @@ -401,7 +487,18 @@ GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes", "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); if (memswlimit >= _unlimited_memory) { - log_trace(os, container)("Memory and Swap Limit is: Unlimited"); + log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); + if (memory->is_hierarchical()) { + const char* matchline = "hierarchical_memsw_limit"; + char* format = "%s " JULONG_FORMAT; + GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline, + "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit) + if (hier_memlimit >= _unlimited_memory) { + log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); + } else { + return (jlong)hier_memlimit; + } + } return (jlong)-1; } else { return (jlong)memswlimit; diff -r 221a589c52ee -r 4649818834e0 src/hotspot/os/linux/osContainer_linux.hpp --- a/src/hotspot/os/linux/osContainer_linux.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/os/linux/osContainer_linux.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -42,6 +42,7 @@ static inline bool is_containerized(); static const char * container_type(); + static jlong uses_mem_hierarchy(); static jlong memory_limit_in_bytes(); static jlong memory_and_swap_limit_in_bytes(); static jlong memory_soft_limit_in_bytes(); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/os/windows/os_windows.cpp --- a/src/hotspot/os/windows/os_windows.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/os/windows/os_windows.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -5000,17 +5000,13 @@ char *addr, size_t bytes, bool read_only, bool allow_exec) { // This OS does not allow existing memory maps to be remapped so we - // have to unmap the memory before we remap it. - if (!os::unmap_memory(addr, bytes)) { - return NULL; - } - - // There is a very small theoretical window between the unmap_memory() - // call above and the map_memory() call below where a thread in native - // code may be able to access an address that is no longer mapped. - - return os::map_memory(fd, file_name, file_offset, addr, bytes, - read_only, allow_exec); + // would have to unmap the memory before we remap it. + + // Because there is a small window between unmapping memory and mapping + // it in again with different protections, CDS archives are mapped RW + // on windows, so this function isn't called. + ShouldNotReachHere(); + return NULL; } diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/adlc/formssel.cpp --- a/src/hotspot/share/adlc/formssel.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/adlc/formssel.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -774,10 +774,16 @@ !strcmp(_matrule->_rChild->_opType,"CheckCastPP") || !strcmp(_matrule->_rChild->_opType,"GetAndSetP") || !strcmp(_matrule->_rChild->_opType,"GetAndSetN") || +#if INCLUDE_ZGC + !strcmp(_matrule->_rChild->_opType,"LoadBarrierSlowReg") || + !strcmp(_matrule->_rChild->_opType,"LoadBarrierWeakSlowReg") || +#endif +#if INCLUDE_SHENANDOAHGC + !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") || + !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") || +#endif !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") || - !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN") || - !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") || - !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN"))) return true; + !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true; else if ( is_ideal_load() == Form::idealP ) return true; else if ( is_ideal_store() != Form::none ) return true; diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/classfile/classFileParser.cpp --- a/src/hotspot/share/classfile/classFileParser.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/classfile/classFileParser.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -5975,9 +5975,9 @@ _minor_version = stream->get_u2_fast(); _major_version = stream->get_u2_fast(); - if (DumpSharedSpaces && _major_version < JAVA_1_5_VERSION) { + if (DumpSharedSpaces && _major_version < JAVA_6_VERSION) { ResourceMark rm; - warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s", + warning("Pre JDK 6 class not supported by CDS: %u.%u %s", _major_version, _minor_version, _class_name->as_C_string()); Exceptions::fthrow( THREAD_AND_LOCATION, diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/classfile/javaClasses.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -1714,20 +1714,13 @@ jlong java_lang_Thread::stackSize(oop java_thread) { - if (_stackSize_offset > 0) { - return java_thread->long_field(_stackSize_offset); - } else { - return 0; - } + return java_thread->long_field(_stackSize_offset); } // Write the thread status value to threadStatus field in java.lang.Thread java class. void java_lang_Thread::set_thread_status(oop java_thread, java_lang_Thread::ThreadStatus status) { - // The threadStatus is only present starting in 1.5 - if (_thread_status_offset > 0) { - java_thread->int_field_put(_thread_status_offset, status); - } + java_thread->int_field_put(_thread_status_offset, status); } // Read thread status value from threadStatus field in java.lang.Thread java class. @@ -1737,62 +1730,31 @@ assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() || JavaThread::current()->thread_state() == _thread_in_vm, "Java Thread is not running in vm"); - // The threadStatus is only present starting in 1.5 - if (_thread_status_offset > 0) { - return (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); - } else { - // All we can easily figure out is if it is alive, but that is - // enough info for a valid unknown status. - // These aren't restricted to valid set ThreadStatus values, so - // use JVMTI values and cast. - JavaThread* thr = java_lang_Thread::thread(java_thread); - if (thr == NULL) { - // the thread hasn't run yet or is in the process of exiting - return NEW; - } - return (java_lang_Thread::ThreadStatus)JVMTI_THREAD_STATE_ALIVE; - } + return (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); } jlong java_lang_Thread::thread_id(oop java_thread) { - // The thread ID field is only present starting in 1.5 - if (_tid_offset > 0) { - return java_thread->long_field(_tid_offset); - } else { - return 0; - } + return java_thread->long_field(_tid_offset); } oop java_lang_Thread::park_blocker(oop java_thread) { - assert(JDK_Version::current().supports_thread_park_blocker() && - _park_blocker_offset != 0, "Must support parkBlocker field"); - - if (_park_blocker_offset > 0) { - return java_thread->obj_field(_park_blocker_offset); - } - - return NULL; + assert(JDK_Version::current().supports_thread_park_blocker(), + "Must support parkBlocker field"); + + return java_thread->obj_field(_park_blocker_offset); } jlong java_lang_Thread::park_event(oop java_thread) { - if (_park_event_offset > 0) { - return java_thread->long_field(_park_event_offset); - } - return 0; + return java_thread->long_field(_park_event_offset); } bool java_lang_Thread::set_park_event(oop java_thread, jlong ptr) { - if (_park_event_offset > 0) { - java_thread->long_field_put(_park_event_offset, ptr); - return true; - } - return false; -} - + java_thread->long_field_put(_park_event_offset, ptr); + return true; +} const char* java_lang_Thread::thread_status_name(oop java_thread) { - assert(_thread_status_offset != 0, "Must have thread status"); ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); switch (status) { case NEW : return "NEW"; diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP + +#include "memory/iterator.hpp" + +class ShenandoahHeap; +class ShenandoahMarkingContext; +class Thread; + +class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { +private: + ShenandoahMarkingContext* const _mark_context; +public: + inline ShenandoahForwardedIsAliveClosure(); + inline bool do_object_b(oop obj); +}; + +class ShenandoahIsAliveClosure: public BoolObjectClosure { +private: + ShenandoahMarkingContext* const _mark_context; +public: + inline ShenandoahIsAliveClosure(); + inline bool do_object_b(oop obj); +}; + +class ShenandoahIsAliveSelector : public StackObj { +private: + ShenandoahIsAliveClosure _alive_cl; + ShenandoahForwardedIsAliveClosure _fwd_alive_cl; +public: + inline BoolObjectClosure* is_alive_closure(); +}; + +class ShenandoahUpdateRefsClosure: public OopClosure { +private: + ShenandoahHeap* _heap; +public: + inline ShenandoahUpdateRefsClosure(); + inline void do_oop(oop* p); + inline void do_oop(narrowOop* p); +private: + template + inline void do_oop_work(T* p); +}; + +class ShenandoahEvacuateUpdateRootsClosure: public BasicOopIterateClosure { +private: + ShenandoahHeap* _heap; + Thread* _thread; +public: + inline ShenandoahEvacuateUpdateRootsClosure(); + inline void do_oop(oop* p); + inline void do_oop(narrowOop* p); + +private: + template + inline void do_oop_work(T* p); +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP + +#include "gc/shenandoah/shenandoahAsserts.hpp" +#include "gc/shenandoah/shenandoahClosures.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "oops/compressedOops.inline.hpp" +#include "runtime/thread.hpp" + +ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : + _mark_context(ShenandoahHeap::heap()->marking_context()) { +} + +bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { + if (CompressedOops::is_null(obj)) { + return false; + } + obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + shenandoah_assert_not_forwarded_if(NULL, obj, + (ShenandoahHeap::heap()->is_concurrent_mark_in_progress() || + ShenandoahHeap::heap()->is_concurrent_traversal_in_progress())); + return _mark_context->is_marked(obj); +} + +ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : + _mark_context(ShenandoahHeap::heap()->marking_context()) { +} + +bool ShenandoahIsAliveClosure::do_object_b(oop obj) { + if (CompressedOops::is_null(obj)) { + return false; + } + shenandoah_assert_not_forwarded(NULL, obj); + return _mark_context->is_marked(obj); +} + +BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() { + return ShenandoahHeap::heap()->has_forwarded_objects() ? + reinterpret_cast(&_fwd_alive_cl) : + reinterpret_cast(&_alive_cl); +} + +ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() : + _heap(ShenandoahHeap::heap()) { +} + +template +void ShenandoahUpdateRefsClosure::do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + _heap->update_with_forwarded_not_null(p, obj); + } +} + +void ShenandoahUpdateRefsClosure::do_oop(oop* p) { do_oop_work(p); } +void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); } + +ShenandoahEvacuateUpdateRootsClosure::ShenandoahEvacuateUpdateRootsClosure() : + _heap(ShenandoahHeap::heap()), _thread(Thread::current()) { +} + +template +void ShenandoahEvacuateUpdateRootsClosure::do_oop_work(T* p) { + assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress"); + + T o = RawAccess<>::oop_load(p); + if (! CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (_heap->in_collection_set(obj)) { + shenandoah_assert_marked(p, obj); + oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + if (oopDesc::equals_raw(resolved, obj)) { + resolved = _heap->evacuate_object(obj, _thread); + } + RawAccess::oop_store(p, resolved); + } + } +} +void ShenandoahEvacuateUpdateRootsClosure::do_oop(oop* p) { + do_oop_work(p); +} + +void ShenandoahEvacuateUpdateRootsClosure::do_oop(narrowOop* p) { + do_oop_work(p); +} + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -33,6 +33,7 @@ #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" #include "gc/shenandoah/shenandoahMarkCompact.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -33,6 +33,7 @@ #include "gc/shenandoah/shenandoahAllocTracker.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBrooksPointer.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" @@ -70,8 +71,6 @@ #include "runtime/vmThread.hpp" #include "services/mallocTracker.hpp" -ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() : _heap(ShenandoahHeap::heap()) {} - #ifdef ASSERT template void ShenandoahAssertToSpaceClosure::do_oop_work(T* p) { @@ -940,43 +939,6 @@ return CollectedHeap::min_dummy_object_size() + ShenandoahBrooksPointer::word_size(); } -class ShenandoahEvacuateUpdateRootsClosure: public BasicOopIterateClosure { -private: - ShenandoahHeap* _heap; - Thread* _thread; -public: - ShenandoahEvacuateUpdateRootsClosure() : - _heap(ShenandoahHeap::heap()), _thread(Thread::current()) { - } - -private: - template - void do_oop_work(T* p) { - assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress"); - - T o = RawAccess<>::oop_load(p); - if (! CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (_heap->in_collection_set(obj)) { - shenandoah_assert_marked(p, obj); - oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); - if (oopDesc::equals_raw(resolved, obj)) { - resolved = _heap->evacuate_object(obj, _thread); - } - RawAccess::oop_store(p, resolved); - } - } - } - -public: - void do_oop(oop* p) { - do_oop_work(p); - } - void do_oop(narrowOop* p) { - do_oop_work(p); - } -}; - class ShenandoahConcurrentEvacuateRegionObjectClosure : public ObjectClosure { private: ShenandoahHeap* const _heap; @@ -1884,31 +1846,6 @@ return result; } -ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} - -ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} - -bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { - if (CompressedOops::is_null(obj)) { - return false; - } - obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); - shenandoah_assert_not_forwarded_if(NULL, obj, ShenandoahHeap::heap()->is_concurrent_mark_in_progress() || ShenandoahHeap::heap()->is_concurrent_traversal_in_progress()); - return _mark_context->is_marked(obj); -} - -bool ShenandoahIsAliveClosure::do_object_b(oop obj) { - if (CompressedOops::is_null(obj)) { - return false; - } - shenandoah_assert_not_forwarded(NULL, obj); - return _mark_context->is_marked(obj); -} - void ShenandoahHeap::ref_processing_init() { assert(_max_workers > 0, "Sanity"); @@ -2879,8 +2816,3 @@ ptrdiff_t ShenandoahHeap::cell_header_size() const { return ShenandoahBrooksPointer::byte_size(); } - -BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() { - return ShenandoahHeap::heap()->has_forwarded_objects() ? reinterpret_cast(&_fwd_alive_cl) - : reinterpret_cast(&_alive_cl); -} diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -91,19 +91,6 @@ virtual bool is_thread_safe() { return false; } }; -class ShenandoahUpdateRefsClosure: public OopClosure { -private: - ShenandoahHeap* _heap; - - template - inline void do_oop_work(T* p); - -public: - ShenandoahUpdateRefsClosure(); - inline void do_oop(oop* p); - inline void do_oop(narrowOop* p); -}; - #ifdef ASSERT class ShenandoahAssertToSpaceClosure : public OopClosure { private: @@ -115,29 +102,6 @@ }; #endif -class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { -private: - ShenandoahMarkingContext* const _mark_context; -public: - ShenandoahForwardedIsAliveClosure(); - bool do_object_b(oop obj); -}; - -class ShenandoahIsAliveClosure: public BoolObjectClosure { -private: - ShenandoahMarkingContext* const _mark_context; -public: - ShenandoahIsAliveClosure(); - bool do_object_b(oop obj); -}; - -class ShenandoahIsAliveSelector : public StackObj { -private: - ShenandoahIsAliveClosure _alive_cl; - ShenandoahForwardedIsAliveClosure _fwd_alive_cl; -public: - BoolObjectClosure* is_alive_closure(); -}; // Shenandoah GC is low-pause concurrent GC that uses Brooks forwarding pointers // to encode forwarding data. See BrooksPointer for details on forwarding data encoding. diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -46,17 +46,6 @@ #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" -template -void ShenandoahUpdateRefsClosure::do_oop_work(T* p) { - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - _heap->update_with_forwarded_not_null(p, obj); - } -} - -void ShenandoahUpdateRefsClosure::do_oop(oop* p) { do_oop_work(p); } -void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); } inline ShenandoahHeapRegion* ShenandoahRegionIterator::next() { size_t new_index = Atomic::add((size_t) 1, &_index); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -27,6 +27,7 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" @@ -242,10 +243,7 @@ _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)), _srs(n_workers), _phase(phase), - _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()), - _par_state_string(StringTable::weak_storage()) - -{ + _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()) { heap->phase_timings()->record_workers_start(_phase); if (ShenandoahStringDedup::is_enabled()) { StringDedup::gc_prologue(false); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -119,7 +119,6 @@ StrongRootsScope _srs; ShenandoahPhaseTimings::Phase _phase; ShenandoahCsetCodeRootsIterator _coderoots_cset_iterator; - OopStorage::ParState _par_state_string; enum Shenandoah_evacuate_roots_tasks { SHENANDOAH_EVAC_Universe_oops_do, diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -30,6 +30,7 @@ #include "gc/shared/workgroup.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/z/zBarrierSetNMethod.cpp --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -55,11 +55,7 @@ // Heal oops and disarm ZNMethodOopClosure cl; - nm->oops_do(&cl); - nm->fix_oop_relocations(); - - OrderAccess::release(); - + ZNMethod::nmethod_oops_do(nm, &cl); disarm(nm); return true; diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/gc/z/zUnload.cpp --- a/src/hotspot/share/gc/z/zUnload.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/gc/z/zUnload.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -71,7 +71,7 @@ ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); ZLocker locker(lock); ZIsUnloadingOopClosure cl; - nm->oops_do(&cl, true /* allow_zombie */); + ZNMethod::nmethod_oops_do(nm, &cl); return cl.is_unloading(); } }; diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -359,7 +359,7 @@ } bool ret = false; - thread->set_trace_flag(); + thread->set_trace_flag(); // Provides StoreLoad, needed to keep read of thread state from floating up. if (JAVA_SAMPLE == type) { if (thread_state_in_java(thread)) { ret = sample_thread_in_java(thread, frames, max_frames); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/memory/filemap.cpp --- a/src/hotspot/share/memory/filemap.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/memory/filemap.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -806,13 +806,14 @@ addr, size, false /* !read_only */, si->_allow_exec); close(); + // These have to be errors because the shared region is now unmapped. if (base == NULL) { - fail_continue("Unable to remap shared readonly space (errno=%d).", errno); - return false; + log_error(cds)("Unable to remap shared readonly space (errno=%d).", errno); + vm_exit(1); } if (base != addr) { - fail_continue("Unable to remap shared readonly space at required address."); - return false; + log_error(cds)("Unable to remap shared readonly space (errno=%d).", errno); + vm_exit(1); } si->_read_only = false; return true; @@ -849,10 +850,17 @@ size_t size = align_up(used, alignment); char *requested_addr = region_addr(i); - // If a tool agent is in use (debugging enabled), we must map the address space RW - if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) { +#ifdef _WINDOWS + // Windows cannot remap read-only shared memory to read-write when required for + // RedefineClasses, which is also used by JFR. Always map windows regions as RW. + si->_read_only = false; +#else + // If a tool agent is in use (debugging enabled), or JFR, we must map the address space RW + if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space() || + Arguments::has_jfr_option()) { si->_read_only = false; } +#endif // _WINDOWS // map the contents of the CDS archive in this memory char *base = os::map_memory(_fd, _full_path, si->_file_offset, @@ -868,7 +876,6 @@ MemTracker::record_virtual_memory_type((address)base, mtClassShared); #endif - if (!verify_region_checksum(i)) { return NULL; } diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/memory/universe.cpp --- a/src/hotspot/share/memory/universe.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/memory/universe.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -1151,6 +1151,8 @@ verify_flags |= Verify_JNIHandles; } else if (strcmp(token, "codecache_oops") == 0) { verify_flags |= Verify_CodeCacheOops; + } else if (strcmp(token, "resolved_method_table") == 0) { + verify_flags |= Verify_ResolvedMethodTable; } else { vm_exit_during_initialization(err_msg("VerifySubSet: \'%s\' memory sub-system is unknown, please correct it", token)); } @@ -1230,6 +1232,10 @@ log_debug(gc, verify)("CodeCache Oops"); CodeCache::verify_oops(); } + if (should_verify_subset(Verify_ResolvedMethodTable)) { + log_debug(gc, verify)("ResolvedMethodTable Oops"); + ResolvedMethodTable::verify(); + } _verify_in_progress = false; } diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/memory/universe.hpp --- a/src/hotspot/share/memory/universe.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/memory/universe.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -478,6 +478,7 @@ Verify_MetaspaceUtils = 128, Verify_JNIHandles = 256, Verify_CodeCacheOops = 512, + Verify_ResolvedMethodTable = 1024, Verify_All = -1 }; static void initialize_verify_flags(); diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/prims/resolvedMethodTable.cpp --- a/src/hotspot/share/prims/resolvedMethodTable.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -346,16 +346,6 @@ // cleaning. Note it might trigger a resize instead. void ResolvedMethodTable::finish_dead_counter() { check_concurrent_work(); - -#ifdef ASSERT - if (SafepointSynchronize::is_at_safepoint()) { - size_t fail_cnt = verify_and_compare_entries(); - if (fail_cnt != 0) { - tty->print_cr("ERROR: fail_cnt=" SIZE_FORMAT, fail_cnt); - guarantee(fail_cnt == 0, "unexpected ResolvedMethodTable verification failures"); - } - } -#endif // ASSERT } #if INCLUDE_JVMTI @@ -402,26 +392,16 @@ } #endif // INCLUDE_JVMTI -// Verification and comp -class VerifyCompResolvedMethod : StackObj { - GrowableArray* _oops; +// Verification +class VerifyResolvedMethod : StackObj { public: - size_t _errors; - VerifyCompResolvedMethod(GrowableArray* oops) : _oops(oops), _errors(0) {} bool operator()(WeakHandle* val) { - oop s = val->peek(); - if (s == NULL) { - return true; + oop obj = val->peek(); + if (obj != NULL) { + Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(obj); + guarantee(method->is_method(), "Must be"); + guarantee(!method->is_old(), "Must be"); } - int len = _oops->length(); - for (int i = 0; i < len; i++) { - bool eq = s == _oops->at(i); - assert(!eq, "Duplicate entries"); - if (eq) { - _errors++; - } - } - _oops->push(s); return true; }; }; @@ -430,16 +410,9 @@ return _items_count; } -size_t ResolvedMethodTable::verify_and_compare_entries() { - Thread* thr = Thread::current(); - GrowableArray* oops = - new (ResourceObj::C_HEAP, mtInternal) - GrowableArray((int)_current_size, true); - - VerifyCompResolvedMethod vcs(oops); - if (!_local_table->try_scan(thr, vcs)) { +void ResolvedMethodTable::verify() { + VerifyResolvedMethod vcs; + if (!_local_table->try_scan(Thread::current(), vcs)) { log_info(membername, table)("verify unavailable at this moment"); } - delete oops; - return vcs._errors; } diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/prims/resolvedMethodTable.hpp --- a/src/hotspot/share/prims/resolvedMethodTable.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/prims/resolvedMethodTable.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -96,7 +96,7 @@ // Debugging static size_t items_count(); - static size_t verify_and_compare_entries(); + static void verify(); }; #endif // SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/runtime/arguments.cpp --- a/src/hotspot/share/runtime/arguments.cpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/runtime/arguments.cpp Fri Apr 19 08:00:42 2019 -0400 @@ -271,17 +271,25 @@ } #if INCLUDE_JFR +static bool _has_jfr_option = false; // is using JFR + // return true on failure static bool match_jfr_option(const JavaVMOption** option) { assert((*option)->optionString != NULL, "invariant"); char* tail = NULL; if (match_option(*option, "-XX:StartFlightRecording", (const char**)&tail)) { + _has_jfr_option = true; return Jfr::on_start_flight_recording_option(option, tail); } else if (match_option(*option, "-XX:FlightRecorderOptions", (const char**)&tail)) { + _has_jfr_option = true; return Jfr::on_flight_recorder_option(option, tail); } return false; } + +bool Arguments::has_jfr_option() { + return _has_jfr_option; +} #endif static void logOption(const char* opt) { diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/runtime/arguments.hpp --- a/src/hotspot/share/runtime/arguments.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/runtime/arguments.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -649,6 +649,8 @@ static bool check_unsupported_cds_runtime_properties() NOT_CDS_RETURN0; static bool atojulong(const char *s, julong* result); + + static bool has_jfr_option() NOT_JFR_RETURN_(false); }; // Disable options not supported in this release, with a warning if they diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/runtime/thread.hpp --- a/src/hotspot/share/runtime/thread.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/runtime/thread.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -1415,7 +1415,7 @@ // Whenever a thread transitions from native to vm/java it must suspend // if external|deopt suspend is present. bool is_suspend_after_native() const { - return (_suspend_flags & (_external_suspend | _deopt_suspend)) != 0; + return (_suspend_flags & (_external_suspend | _deopt_suspend JFR_ONLY(| _trace_flag))) != 0; } // external suspend request is completed diff -r 221a589c52ee -r 4649818834e0 src/hotspot/share/utilities/macros.hpp --- a/src/hotspot/share/utilities/macros.hpp Fri Apr 19 07:55:28 2019 -0400 +++ b/src/hotspot/share/utilities/macros.hpp Fri Apr 19 08:00:42 2019 -0400 @@ -279,8 +279,10 @@ #if INCLUDE_JFR #define JFR_ONLY(code) code +#define NOT_JFR_RETURN_(code) /* next token must be ; */ #else #define JFR_ONLY(code) +#define NOT_JFR_RETURN_(code) { return code; } #endif #ifndef INCLUDE_JVMCI diff -r 221a589c52ee -r 4649818834e0 src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java --- a/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java Fri Apr 19 08:00:42 2019 -0400 @@ -25,15 +25,16 @@ package jdk.internal.platform.cgroupv1; -import java.io.BufferedReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Stream; +import jdk.internal.platform.cgroupv1.SubSystem.MemorySubSystem; + public class Metrics implements jdk.internal.platform.Metrics { - private SubSystem memory; + private MemorySubSystem memory; private SubSystem cpu; private SubSystem cpuacct; private SubSystem cpuset; @@ -133,7 +134,7 @@ for (String subsystemName: subsystemNames) { switch (subsystemName) { case "memory": - metric.setMemorySubSystem(new SubSystem(mountentry[3], mountentry[4])); + metric.setMemorySubSystem(new MemorySubSystem(mountentry[3], mountentry[4])); break; case "cpuset": metric.setCpuSetSubSystem(new SubSystem(mountentry[3], mountentry[4])); @@ -195,6 +196,11 @@ if (subsystem != null) { subsystem.setPath(base); + if (subsystem instanceof MemorySubSystem) { + MemorySubSystem memorySubSystem = (MemorySubSystem)subsystem; + boolean isHierarchial = getHierarchical(memorySubSystem); + memorySubSystem.setHierarchical(isHierarchial); + } metric.setActiveSubSystems(); } if (subsystem2 != null) { @@ -203,6 +209,11 @@ } + private static boolean getHierarchical(MemorySubSystem subsystem) { + long hierarchical = SubSystem.getLongValue(subsystem, "memory.use_hierarchy"); + return hierarchical > 0; + } + private void setActiveSubSystems() { activeSubSystems = true; } @@ -211,7 +222,7 @@ return activeSubSystems; } - private void setMemorySubSystem(SubSystem memory) { + private void setMemorySubSystem(MemorySubSystem memory) { this.memory = memory; } @@ -366,9 +377,29 @@ public long getMemoryLimit() { long retval = SubSystem.getLongValue(memory, "memory.limit_in_bytes"); + if (retval > unlimited_minimum) { + if (memory.isHierarchical()) { + // memory.limit_in_bytes returned unlimited, attempt + // hierarchical memory limit + String match = "hierarchical_memory_limit"; + retval = SubSystem.getLongValueMatchingLine(memory, + "memory.stat", + match, + Metrics::convertHierachicalLimitLine); + } + } return retval > unlimited_minimum ? -1L : retval; } + public static long convertHierachicalLimitLine(String line) { + String[] tokens = line.split("\\s"); + if (tokens.length == 2) { + String strVal = tokens[1]; + return SubSystem.convertStringToLong(strVal); + } + return unlimited_minimum + 1; // unlimited + } + public long getMemoryMaxUsage() { return SubSystem.getLongValue(memory, "memory.max_usage_in_bytes"); } @@ -417,6 +448,17 @@ public long getMemoryAndSwapLimit() { long retval = SubSystem.getLongValue(memory, "memory.memsw.limit_in_bytes"); + if (retval > unlimited_minimum) { + if (memory.isHierarchical()) { + // memory.memsw.limit_in_bytes returned unlimited, attempt + // hierarchical memory limit + String match = "hierarchical_memsw_limit"; + retval = SubSystem.getLongValueMatchingLine(memory, + "memory.stat", + match, + Metrics::convertHierachicalLimitLine); + } + } return retval > unlimited_minimum ? -1L : retval; } diff -r 221a589c52ee -r 4649818834e0 src/java.base/linux/classes/jdk/internal/platform/cgroupv1/SubSystem.java --- a/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/SubSystem.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/SubSystem.java Fri Apr 19 08:00:42 2019 -0400 @@ -29,10 +29,11 @@ import java.io.IOException; import java.math.BigInteger; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Stream; public class SubSystem { @@ -99,10 +100,32 @@ } + public static long getLongValueMatchingLine(SubSystem subsystem, + String param, + String match, + Function conversion) { + long retval = Metrics.unlimited_minimum + 1; // default unlimited + try { + List lines = Files.readAllLines(Paths.get(subsystem.path(), param)); + for (String line: lines) { + if (line.contains(match)) { + retval = conversion.apply(line); + break; + } + } + } catch (IOException e) { + // Ignore. Default is unlimited. + } + return retval; + } + public static long getLongValue(SubSystem subsystem, String parm) { String strval = getStringValue(subsystem, parm); + return convertStringToLong(strval); + } + + public static long convertStringToLong(String strval) { long retval = 0; - if (strval == null) return 0L; try { @@ -215,4 +238,22 @@ return ints; } + + public static class MemorySubSystem extends SubSystem { + + private boolean hierarchical; + + public MemorySubSystem(String root, String mountPoint) { + super(root, mountPoint); + } + + boolean isHierarchical() { + return hierarchical; + } + + void setHierarchical(boolean hierarchical) { + this.hierarchical = hierarchical; + } + + } } diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/java/lang/String.java --- a/src/java.base/share/classes/java/lang/String.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/java/lang/String.java Fri Apr 19 08:00:42 2019 -0400 @@ -1965,20 +1965,7 @@ if (str.isEmpty()) { return this; } - if (coder() == str.coder()) { - byte[] val = this.value; - byte[] oval = str.value; - int len = val.length + oval.length; - byte[] buf = Arrays.copyOf(val, len); - System.arraycopy(oval, 0, buf, val.length, oval.length); - return new String(buf, coder); - } - int len = length(); - int olen = str.length(); - byte[] buf = StringUTF16.newBytesFor(len + olen); - getBytes(buf, 0, UTF16); - str.getBytes(buf, len, UTF16); - return new String(buf, UTF16); + return StringConcatHelper.simpleConcat(this, str); } /** diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/java/lang/StringConcatHelper.java --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package java.lang; +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.ForceInline; + /** * Helper for string concatenation. These methods are mostly looked up with private lookups * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle} @@ -38,8 +41,10 @@ /** * Check for overflow, throw exception on overflow. - * @param lengthCoder String length and coder - * @return lengthCoder + * + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @return the given parameter value, if valid */ private static long checkOverflow(long lengthCoder) { if ((int)lengthCoder >= 0) { @@ -50,76 +55,83 @@ /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, boolean value) { - return checkOverflow(current + (value ? 4 : 5)); + static long mix(long lengthCoder, boolean value) { + return checkOverflow(lengthCoder + (value ? 4 : 5)); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, byte value) { - return mix(current, (int)value); + static long mix(long lengthCoder, byte value) { + return mix(lengthCoder, (int)value); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, char value) { - return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16); + static long mix(long lengthCoder, char value) { + return checkOverflow(lengthCoder + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, short value) { - return mix(current, (int)value); + static long mix(long lengthCoder, short value) { + return mix(lengthCoder, (int)value); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, int value) { - return checkOverflow(current + Integer.stringSize(value)); + static long mix(long lengthCoder, int value) { + return checkOverflow(lengthCoder + Integer.stringSize(value)); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, long value) { - return checkOverflow(current + Long.stringSize(value)); + static long mix(long lengthCoder, long value) { + return checkOverflow(lengthCoder + Long.stringSize(value)); } /** * Mix value length and coder into current length and coder. - * @param current current length - * @param value value to mix in - * @return new length and coder + * @param lengthCoder String length with coder packed into higher bits + * the upper word. + * @param value value to mix in + * @return new length and coder */ - static long mix(long current, String value) { - current += value.length(); + static long mix(long lengthCoder, String value) { + lengthCoder += value.length(); if (value.coder() == String.UTF16) { - current |= UTF16; + lengthCoder |= UTF16; } - return checkOverflow(current); + return checkOverflow(lengthCoder); } /** @@ -285,10 +297,62 @@ } } + /** + * Perform a simple concatenation between two objects. Added for startup + * performance, but also demonstrates the code that would be emitted by + * {@code java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy} + * for two Object arguments. + * + * @param first first argument + * @param second second argument + * @return String resulting string + */ + @ForceInline + static String simpleConcat(Object first, Object second) { + String s1 = stringOf(first); + String s2 = stringOf(second); + // start "mixing" in length and coder or arguments, order is not + // important + long indexCoder = mix(initialCoder(), s2); + indexCoder = mix(indexCoder, s1); + byte[] buf = newArray(indexCoder); + // prepend each argument in reverse order, since we prepending + // from the end of the byte array + indexCoder = prepend(indexCoder, buf, s2); + indexCoder = prepend(indexCoder, buf, s1); + return newString(buf, indexCoder); + } + + /** + * We need some additional conversion for Objects in general, because + * {@code String.valueOf(Object)} may return null. String conversion rules + * in Java state we need to produce "null" String in this case, so we + * provide a customized version that deals with this problematic corner case. + */ + static String stringOf(Object value) { + String s; + return (value == null || (s = value.toString()) == null) ? "null" : s; + } + private static final long LATIN1 = (long)String.LATIN1 << 32; private static final long UTF16 = (long)String.UTF16 << 32; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + /** + * Allocates an uninitialized byte array based on the length and coder information + * in indexCoder + * @param indexCoder + * @return the newly allocated byte array + */ + @ForceInline + static byte[] newArray(long indexCoder) { + byte coder = (byte)(indexCoder >> 32); + int index = (int)indexCoder; + return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); + } + /** * Provides the initial coder for the String. * @return initial coder, adjusted into the upper half diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package java.lang.invoke; import jdk.internal.misc.Unsafe; +import jdk.internal.misc.VM; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.MethodVisitor; @@ -191,6 +192,8 @@ */ private static final ProxyClassesDumper DUMPER; + private static final Class STRING_HELPER; + static { // In case we need to double-back onto the StringConcatFactory during this // static initialization, make sure we have the reasonable defaults to complete @@ -202,15 +205,20 @@ // DEBUG = false; // implied // DUMPER = null; // implied - Properties props = GetPropertyAction.privilegedGetProperties(); + try { + STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); + } catch (Throwable e) { + throw new AssertionError(e); + } + final String strategy = - props.getProperty("java.lang.invoke.stringConcat"); + VM.getSavedProperty("java.lang.invoke.stringConcat"); CACHE_ENABLE = Boolean.parseBoolean( - props.getProperty("java.lang.invoke.stringConcat.cache")); + VM.getSavedProperty("java.lang.invoke.stringConcat.cache")); DEBUG = Boolean.parseBoolean( - props.getProperty("java.lang.invoke.stringConcat.debug")); + VM.getSavedProperty("java.lang.invoke.stringConcat.debug")); final String dumpPath = - props.getProperty("java.lang.invoke.stringConcat.dumpClasses"); + VM.getSavedProperty("java.lang.invoke.stringConcat.dumpClasses"); STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy); CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null; @@ -1519,6 +1527,33 @@ static MethodHandle generate(MethodType mt, Recipe recipe) throws Throwable { + // Fast-path two-argument Object + Object concatenations + if (recipe.getElements().size() == 2) { + // Two object arguments + if (mt.parameterCount() == 2 && + !mt.parameterType(0).isPrimitive() && + !mt.parameterType(1).isPrimitive()) { + return SIMPLE; + } + // One element is a constant + if (mt.parameterCount() == 1 && !mt.parameterType(0).isPrimitive()) { + MethodHandle mh = SIMPLE; + // Insert constant element + + // First recipe element is a constant + if (recipe.getElements().get(0).getTag() == TAG_CONST && + recipe.getElements().get(1).getTag() != TAG_CONST) { + return MethodHandles.insertArguments(mh, 0, + recipe.getElements().get(0).getValue()); + } else if (recipe.getElements().get(1).getTag() == TAG_CONST && + recipe.getElements().get(0).getTag() != TAG_CONST) { + return MethodHandles.insertArguments(mh, 1, + recipe.getElements().get(1).getValue()); + } + // else... fall-through to slow-path + } + } + // Create filters and obtain filtered parameter types. Filters would be used in the beginning // to convert the incoming arguments into the arguments we can process (e.g. Objects -> Strings). // The filtered argument type list is used all over in the combinators below. @@ -1626,13 +1661,6 @@ return mh; } - @ForceInline - private static byte[] newArray(long indexCoder) { - byte coder = (byte)(indexCoder >> 32); - int index = (int)indexCoder; - return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); - } - private static MethodHandle prepender(Class cl) { return PREPENDERS.computeIfAbsent(cl, PREPEND); } @@ -1659,16 +1687,15 @@ } }; + private static final MethodHandle SIMPLE; private static final MethodHandle NEW_STRING; private static final MethodHandle NEW_ARRAY; private static final ConcurrentMap, MethodHandle> PREPENDERS; private static final ConcurrentMap, MethodHandle> MIXERS; private static final long INITIAL_CODER; - static final Class STRING_HELPER; static { try { - STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", long.class); INITIAL_CODER = (long) initCoder.invoke(); } catch (Throwable e) { @@ -1678,8 +1705,9 @@ PREPENDERS = new ConcurrentHashMap<>(); MIXERS = new ConcurrentHashMap<>(); + SIMPLE = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "simpleConcat", String.class, Object.class, Object.class); NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class); - NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, long.class); + NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newArray", byte[].class, long.class); } } @@ -1692,22 +1720,8 @@ // no instantiation } - private static class ObjectStringifier { - - // We need some additional conversion for Objects in general, because String.valueOf(Object) - // may return null. String conversion rules in Java state we need to produce "null" String - // in this case, so we provide a customized version that deals with this problematic corner case. - private static String valueOf(Object value) { - String s; - return (value == null || (s = value.toString()) == null) ? "null" : s; - } - - // Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact - // java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API. - private static final MethodHandle INSTANCE = - lookupStatic(Lookup.IMPL_LOOKUP, ObjectStringifier.class, "valueOf", String.class, Object.class); - - } + private static final MethodHandle OBJECT_INSTANCE = + lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "stringOf", String.class, Object.class); private static class FloatStringifiers { private static final MethodHandle FLOAT_INSTANCE = @@ -1751,7 +1765,7 @@ */ static MethodHandle forMost(Class t) { if (!t.isPrimitive()) { - return ObjectStringifier.INSTANCE; + return OBJECT_INSTANCE; } else if (t == float.class) { return FloatStringifiers.FLOAT_INSTANCE; } else if (t == double.class) { diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/java/math/BigDecimal.java --- a/src/java.base/share/classes/java/math/BigDecimal.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/java/math/BigDecimal.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3414,9 +3414,32 @@ */ @Override public long longValue(){ - return (intCompact != INFLATED && scale == 0) ? - intCompact: - toBigInteger().longValue(); + if (intCompact != INFLATED && scale == 0) { + return intCompact; + } else { + // Fastpath zero and small values + if (this.signum() == 0 || fractionOnly() || + // Fastpath very large-scale values that will result + // in a truncated value of zero. If the scale is -64 + // or less, there are at least 64 powers of 10 in the + // value of the numerical result. Since 10 = 2*5, in + // that case there would also be 64 powers of 2 in the + // result, meaning all 64 bits of a long will be zero. + scale <= -64) { + return 0; + } else { + return toBigInteger().longValue(); + } + } + } + + /** + * Return true if a nonzero BigDecimal has an absolute value less + * than one; i.e. only has fraction digits. + */ + private boolean fractionOnly() { + assert this.signum() != 0; + return (this.precision() - this.scale) <= 0; } /** @@ -3434,15 +3457,20 @@ public long longValueExact() { if (intCompact != INFLATED && scale == 0) return intCompact; + + // Fastpath zero + if (this.signum() == 0) + return 0; + + // Fastpath numbers less than 1.0 (the latter can be very slow + // to round if very small) + if (fractionOnly()) + throw new ArithmeticException("Rounding necessary"); + // If more than 19 digits in integer part it cannot possibly fit if ((precision() - scale) > 19) // [OK for negative scale too] throw new java.lang.ArithmeticException("Overflow"); - // Fastpath zero and < 1.0 numbers (the latter can be very slow - // to round if very small) - if (this.signum() == 0) - return 0; - if ((this.precision() - this.scale) <= 0) - throw new ArithmeticException("Rounding necessary"); + // round to an integer, with Exception if decimal part non-0 BigDecimal num = this.setScale(0, ROUND_UNNECESSARY); if (num.precision() >= 19) // need to check carefully @@ -3486,7 +3514,7 @@ public int intValue() { return (intCompact != INFLATED && scale == 0) ? (int)intCompact : - toBigInteger().intValue(); + (int)longValue(); } /** diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/java/time/chrono/JapaneseEra.java --- a/src/java.base/share/classes/java/time/chrono/JapaneseEra.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/java/time/chrono/JapaneseEra.java Fri Apr 19 08:00:42 2019 -0400 @@ -154,6 +154,8 @@ * The singleton instance for the 'Reiwa' era (2019-05-01 - ) * which has the value 3. The end date of this era is not specified, unless * the Japanese Government defines it. + * + * @since 13 */ public static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1)); diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/sun/nio/cs/StreamDecoder.java --- a/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,20 @@ package sun.nio.cs; -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.charset.*; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.IllegalCharsetNameException; public class StreamDecoder extends Reader { @@ -190,8 +200,11 @@ synchronized (lock) { if (closed) return; - implClose(); - closed = true; + try { + implClose(); + } finally { + closed = true; + } } } diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/sun/nio/cs/StreamEncoder.java --- a/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,21 @@ * questions. */ -/* - */ - package sun.nio.cs; -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.charset.*; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.IllegalCharsetNameException; public class StreamEncoder extends Writer { @@ -158,8 +164,11 @@ synchronized (lock) { if (closed) return; - implClose(); - closed = true; + try { + implClose(); + } finally { + closed = true; + } } } @@ -337,8 +346,13 @@ writeBytes(); if (ch != null) ch.close(); - else - out.close(); + else { + try { + out.flush(); + } finally { + out.close(); + } + } } catch (IOException x) { encoder.reset(); throw x; diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Apr 19 08:00:42 2019 -0400 @@ -980,7 +980,7 @@ } try { - shutdownInput(false); + SSLSocketImpl.this.close(); } catch (IOException ioe) { // ignore the exception if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { @@ -1146,7 +1146,7 @@ } try { - shutdownOutput(); + SSLSocketImpl.this.close(); } catch (IOException ioe) { // ignore the exception if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { diff -r 221a589c52ee -r 4649818834e0 src/java.base/share/native/libjli/java.c --- a/src/java.base/share/native/libjli/java.c Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.base/share/native/libjli/java.c Fri Apr 19 08:00:42 2019 -0400 @@ -204,11 +204,14 @@ */ static jlong threadStackSize = 0; /* stack size of the new thread */ static jlong maxHeapSize = 0; /* max heap size */ -static jlong initialHeapSize = 0; /* inital heap size */ +static jlong initialHeapSize = 0; /* initial heap size */ /* - * A minimum -Xss stack size suitable for all platforms. - */ + * A minimum initial-thread stack size suitable for most platforms. + * This is the minimum amount of stack needed to load the JVM such + * that it can reject a too small -Xss value. If this is too small + * JVM initialization would cause a StackOverflowError. + */ #ifndef STACK_SIZE_MINIMUM #define STACK_SIZE_MINIMUM (64 * KB) #endif @@ -934,16 +937,18 @@ options[numOptions].optionString = str; options[numOptions++].extraInfo = info; + /* + * -Xss is used both by the JVM and here to establish the stack size of the thread + * created to launch the JVM. In the latter case we need to ensure we don't go + * below the minimum stack size allowed. If -Xss is zero that tells the JVM to use + * 'default' sizes (either from JVM or system configuration, e.g. 'ulimit -s' on linux), + * and is not itself a small stack size that will be rejected. So we ignore -Xss0 here. + */ if (JLI_StrCCmp(str, "-Xss") == 0) { jlong tmp; if (parse_size(str + 4, &tmp)) { threadStackSize = tmp; - /* - * Make sure the thread stack size is big enough that we won't get a stack - * overflow before the JVM startup code can check to make sure the stack - * is big enough. - */ - if (threadStackSize < (jlong)STACK_SIZE_MINIMUM) { + if (threadStackSize > 0 && threadStackSize < (jlong)STACK_SIZE_MINIMUM) { threadStackSize = STACK_SIZE_MINIMUM; } } @@ -2322,38 +2327,38 @@ int argc, char **argv, int mode, char *what, int ret) { - - /* - * If user doesn't specify stack size, check if VM has a preference. - * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will - * return its default stack size through the init args structure. - */ if (threadStackSize == 0) { - struct JDK1_1InitArgs args1_1; - memset((void*)&args1_1, 0, sizeof(args1_1)); - args1_1.version = JNI_VERSION_1_1; - ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ - if (args1_1.javaStackSize > 0) { - threadStackSize = args1_1.javaStackSize; - } + /* + * If the user hasn't specified a non-zero stack size ask the JVM for its default. + * A returned 0 means 'use the system default' for a platform, e.g., Windows. + * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will + * return its default stack size through the init args structure. + */ + struct JDK1_1InitArgs args1_1; + memset((void*)&args1_1, 0, sizeof(args1_1)); + args1_1.version = JNI_VERSION_1_1; + ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ + if (args1_1.javaStackSize > 0) { + threadStackSize = args1_1.javaStackSize; + } } { /* Create a new thread to create JVM and invoke main method */ - JavaMainArgs args; - int rslt; + JavaMainArgs args; + int rslt; - args.argc = argc; - args.argv = argv; - args.mode = mode; - args.what = what; - args.ifn = *ifn; + args.argc = argc; + args.argv = argv; + args.mode = mode; + args.what = what; + args.ifn = *ifn; - rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args); - /* If the caller has deemed there is an error we - * simply return that, otherwise we return the value of - * the callee - */ - return (ret != 0) ? ret : rslt; + rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args); + /* If the caller has deemed there is an error we + * simply return that, otherwise we return the value of + * the callee + */ + return (ret != 0) ? ret : rslt; } } diff -r 221a589c52ee -r 4649818834e0 src/java.base/unix/native/libnio/ch/SocketDispatcher.c diff -r 221a589c52ee -r 4649818834e0 src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java --- a/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,4 +131,18 @@ * effect */ Locale getLocale(); + + /** + * Returns {@code true} if preview features are enabled + * and {@code false} otherwise. + * @return whether or not preview features are enabled + * + * @implSpec The default implementation of this method returns + * {@code false}. + * + * @since 13 + */ + default boolean isPreviewEnabled() { + return false; + } } diff -r 221a589c52ee -r 4649818834e0 src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,8 @@ HttpClient client = http1Exchange.client(); // Filter overridable headers from userHeaders - userHeaders = HttpHeaders.of(userHeaders.map(), Utils.CONTEXT_RESTRICTED(client)); + userHeaders = HttpHeaders.of(userHeaders.map(), + connection.contextRestricted(request, client)); final HttpHeaders uh = userHeaders; diff -r 221a589c52ee -r 4649818834e0 src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java Fri Apr 19 08:00:42 2019 -0400 @@ -285,6 +285,16 @@ } } + BiPredicate contextRestricted(HttpRequestImpl request, HttpClient client) { + if (!isTunnel() && request.isConnect()) { + // establishing a proxy tunnel + assert request.proxy() == null; + return Utils.PROXY_TUNNEL_RESTRICTED(client); + } else { + return Utils.CONTEXT_RESTRICTED(client); + } + } + // Composes a new immutable HttpHeaders that combines the // user and system header but only keeps those headers that // start with "proxy-" diff -r 221a589c52ee -r 4649818834e0 src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java Fri Apr 19 08:00:42 2019 -0400 @@ -178,7 +178,12 @@ ! (k.equalsIgnoreCase("Authorization") && k.equalsIgnoreCase("Proxy-Authorization")); } + private static final BiPredicate HOST_RESTRICTED = (k,v) -> !"host".equalsIgnoreCase(k); + public static final BiPredicate PROXY_TUNNEL_RESTRICTED(HttpClient client) { + return CONTEXT_RESTRICTED(client).and(HOST_RESTRICTED); + } + private static final Predicate IS_HOST = "host"::equalsIgnoreCase; private static final Predicate IS_PROXY_HEADER = (k) -> k != null && k.length() > 6 && "proxy-".equalsIgnoreCase(k.substring(0,6)); private static final Predicate NO_PROXY_HEADER = @@ -250,7 +255,8 @@ public static final BiPredicate PROXY_TUNNEL_FILTER = (s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_TUNNEL_DISABLED_SCHEMES, - IS_PROXY_HEADER); + // Allows Proxy-* and Host headers when establishing the tunnel. + IS_PROXY_HEADER.or(IS_HOST)); public static final BiPredicate PROXY_FILTER = (s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_DISABLED_SCHEMES, ALL_HEADERS); diff -r 221a589c52ee -r 4649818834e0 src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java --- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,8 +58,24 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception { - if (hash != interfaceHash) - throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + if (opnum < 0) { + if (hash == 7583982177005850366L) { + opnum = 0; + } else if (hash == 2571371476350237748L) { + opnum = 1; + } else if (hash == -7538657168040752697L) { + opnum = 2; + } else if (hash == -8381844669958460146L) { + opnum = 3; + } else if (hash == 7305022919901907578L) { + opnum = 4; + } else { + throw new java.rmi.UnmarshalException("invalid method hash"); + } + } else { + if (hash != interfaceHash) + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj; switch (opnum) { diff -r 221a589c52ee -r 4649818834e0 src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java --- a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.rmi.ServerException; import java.rmi.UnmarshalException; import java.rmi.server.ExportException; +import java.rmi.server.Operation; import java.rmi.server.RemoteCall; import java.rmi.server.RemoteRef; import java.rmi.server.RemoteStub; @@ -292,15 +293,14 @@ throw new UnmarshalException("error unmarshalling call header", readEx); } - if (num >= 0) { - if (skel != null) { + if (skel != null) { + // If there is a skeleton, use it oldDispatch(obj, call, num); return; - } else { - throw new UnmarshalException( - "skeleton class not found but required " + - "for client version"); - } + + } else if (num >= 0){ + throw new UnmarshalException( + "skeleton class not found but required for client version"); } try { op = in.readLong(); @@ -428,8 +428,8 @@ /** * Handle server-side dispatch using the RMI 1.1 stub/skeleton - * protocol, given a non-negative operation number that has - * already been read from the call stream. + * protocol, given a non-negative operation number or negative method hash + * that has already been read from the call stream. * Exceptions are handled by the caller to be sent to the remote client. * * @param obj the target remote object for the call @@ -461,7 +461,8 @@ } // if calls are being logged, write out object id and operation - logCall(obj, skel.getOperations()[op]); + Operation[] operations = skel.getOperations(); + logCall(obj, op >= 0 && op < operations.length ? operations[op] : "op: " + op); unmarshalCustomCallData(in); // dispatch to skeleton for remote object skel.dispatch(obj, call, op, hash); diff -r 221a589c52ee -r 4649818834e0 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -22,6 +22,7 @@ import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader; import com.sun.org.apache.xerces.internal.impl.io.UCSReader; +import com.sun.org.apache.xerces.internal.impl.io.UTF16Reader; import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader; import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; @@ -89,7 +90,7 @@ * @author K.Venugopal SUN Microsystems * @author Neeraj Bajaj SUN Microsystems * @author Sunitha Reddy SUN Microsystems - * @LastModified: Nov 2018 + * @LastModified: Apr 2019 */ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { @@ -412,9 +413,6 @@ /** Augmentations for entities. */ private final Augmentations fEntityAugs = new AugmentationsImpl(); - /** Pool of character buffers. */ - private CharacterBufferPool fBufferPool = new CharacterBufferPool(fBufferSize, DEFAULT_INTERNAL_BUFFER_SIZE); - /** indicate whether Catalog should be used for resolving external resources */ private boolean fUseCatalog = true; CatalogFeatures fCatalogFeatures; @@ -694,7 +692,8 @@ } // wrap this stream in RewindableInputStream - stream = new RewindableInputStream(stream); + RewindableInputStream rewindableStream = new RewindableInputStream(stream); + stream = rewindableStream; // perform auto-detect of encoding if necessary if (encoding == null) { @@ -702,27 +701,30 @@ final byte[] b4 = new byte[4]; int count = 0; for (; count<4; count++ ) { - b4[count] = (byte)stream.read(); + b4[count] = (byte)rewindableStream.readAndBuffer(); } if (count == 4) { - Object [] encodingDesc = getEncodingName(b4, count); - encoding = (String)(encodingDesc[0]); - isBigEndian = (Boolean)(encodingDesc[1]); - + final EncodingInfo info = getEncodingInfo(b4, count); + encoding = info.autoDetectedEncoding; + final String readerEncoding = info.readerEncoding; + isBigEndian = info.isBigEndian; stream.reset(); - // Special case UTF-8 files with BOM created by Microsoft - // tools. It's more efficient to consume the BOM than make - // the reader perform extra checks. -Ac - if (count > 2 && encoding.equals("UTF-8")) { - int b0 = b4[0] & 0xFF; - int b1 = b4[1] & 0xFF; - int b2 = b4[2] & 0xFF; - if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { - // ignore first three bytes... + if (info.hasBOM) { + // Special case UTF-8 files with BOM created by Microsoft + // tools. It's more efficient to consume the BOM than make + // the reader perform extra checks. -Ac + if (EncodingInfo.STR_UTF8.equals(readerEncoding)) { + // UTF-8 BOM: 0xEF 0xBB 0xBF stream.skip(3); } + // It's also more efficient to consume the UTF-16 BOM. + else if (EncodingInfo.STR_UTF16.equals(readerEncoding)) { + // UTF-16 BE BOM: 0xFE 0xFF + // UTF-16 LE BOM: 0xFF 0xFE + stream.skip(2); + } } - reader = createReader(stream, encoding, isBigEndian); + reader = createReader(stream, readerEncoding, isBigEndian); } else { reader = createReader(stream, encoding, isBigEndian); } @@ -733,11 +735,11 @@ encoding = encoding.toUpperCase(Locale.ENGLISH); // If encoding is UTF-8, consume BOM if one is present. - if (encoding.equals("UTF-8")) { + if (EncodingInfo.STR_UTF8.equals(encoding)) { final int[] b3 = new int[3]; int count = 0; for (; count < 3; ++count) { - b3[count] = stream.read(); + b3[count] = rewindableStream.readAndBuffer(); if (b3[count] == -1) break; } @@ -750,56 +752,51 @@ stream.reset(); } } - // If encoding is UTF-16, we still need to read the first four bytes - // in order to discover the byte order. - else if (encoding.equals("UTF-16")) { + // If encoding is UTF-16, we still need to read the first + // four bytes, in order to discover the byte order. + else if (EncodingInfo.STR_UTF16.equals(encoding)) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = stream.read(); + b4[count] = rewindableStream.readAndBuffer(); if (b4[count] == -1) break; } stream.reset(); - - String utf16Encoding = "UTF-16"; if (count >= 2) { final int b0 = b4[0]; final int b1 = b4[1]; if (b0 == 0xFE && b1 == 0xFF) { // UTF-16, big-endian - utf16Encoding = "UTF-16BE"; isBigEndian = Boolean.TRUE; + stream.skip(2); } else if (b0 == 0xFF && b1 == 0xFE) { // UTF-16, little-endian - utf16Encoding = "UTF-16LE"; isBigEndian = Boolean.FALSE; + stream.skip(2); } else if (count == 4) { final int b2 = b4[2]; final int b3 = b4[3]; if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { // UTF-16, big-endian, no BOM - utf16Encoding = "UTF-16BE"; isBigEndian = Boolean.TRUE; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { // UTF-16, little-endian, no BOM - utf16Encoding = "UTF-16LE"; isBigEndian = Boolean.FALSE; } } } - reader = createReader(stream, utf16Encoding, isBigEndian); } // If encoding is UCS-4, we still need to read the first four bytes // in order to discover the byte order. - else if (encoding.equals("ISO-10646-UCS-4")) { + else if (EncodingInfo.STR_UCS4.equals(encoding)) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = stream.read(); + b4[count] = rewindableStream.readAndBuffer(); if (b4[count] == -1) break; } @@ -819,11 +816,11 @@ } // If encoding is UCS-2, we still need to read the first four bytes // in order to discover the byte order. - else if (encoding.equals("ISO-10646-UCS-2")) { + else if (EncodingInfo.STR_UCS2.equals(encoding)) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = stream.read(); + b4[count] = rewindableStream.readAndBuffer(); if (b4[count] == -1) break; } @@ -1798,7 +1795,6 @@ bufferSize.intValue() > DEFAULT_XMLDECL_BUFFER_SIZE) { fBufferSize = bufferSize.intValue(); fEntityScanner.setBufferSize(fBufferSize); - fBufferPool.setExternalBufferSize(fBufferSize); } } if (suffixLength == Constants.SECURITY_MANAGER_PROPERTY.length() && @@ -2425,14 +2421,12 @@ * * @param b4 The first four bytes of the input. * @param count The number of bytes actually read. - * @return a 2-element array: the first element, an IANA-encoding string, - * the second element a Boolean which is true iff the document is big endian, false - * if it's little-endian, and null if the distinction isn't relevant. + * @return an instance of EncodingInfo which represents the auto-detected encoding. */ - protected Object[] getEncodingName(byte[] b4, int count) { + protected EncodingInfo getEncodingInfo(byte[] b4, int count) { if (count < 2) { - return defaultEncoding; + return EncodingInfo.UTF_8; } // UTF-16, with BOM @@ -2440,69 +2434,70 @@ int b1 = b4[1] & 0xFF; if (b0 == 0xFE && b1 == 0xFF) { // UTF-16, big-endian - return new Object [] {"UTF-16BE", true}; + return EncodingInfo.UTF_16_BIG_ENDIAN_WITH_BOM; } if (b0 == 0xFF && b1 == 0xFE) { // UTF-16, little-endian - return new Object [] {"UTF-16LE", false}; + return EncodingInfo.UTF_16_LITTLE_ENDIAN_WITH_BOM; } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 3) { - return defaultEncoding; + return EncodingInfo.UTF_8; } // UTF-8 with a BOM int b2 = b4[2] & 0xFF; if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { - return defaultEncoding; + return EncodingInfo.UTF_8_WITH_BOM; } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 4) { - return defaultEncoding; + return EncodingInfo.UTF_8; } // other encodings int b3 = b4[3] & 0xFF; if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { // UCS-4, big endian (1234) - return new Object [] {"ISO-10646-UCS-4", true}; + return EncodingInfo.UCS_4_BIG_ENDIAN; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { // UCS-4, little endian (4321) - return new Object [] {"ISO-10646-UCS-4", false}; + return EncodingInfo.UCS_4_LITTLE_ENDIAN; } if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { // UCS-4, unusual octet order (2143) // REVISIT: What should this be? - return new Object [] {"ISO-10646-UCS-4", null}; + return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { // UCS-4, unusual octect order (3412) // REVISIT: What should this be? - return new Object [] {"ISO-10646-UCS-4", null}; + return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { // UTF-16, big-endian, no BOM // (or could turn out to be UCS-2... // REVISIT: What should this be? - return new Object [] {"UTF-16BE", true}; + return EncodingInfo.UTF_16_BIG_ENDIAN; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { // UTF-16, little-endian, no BOM // (or could turn out to be UCS-2... - return new Object [] {"UTF-16LE", false}; + return EncodingInfo.UTF_16_LITTLE_ENDIAN; } if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { // EBCDIC // a la xerces1, return CP037 instead of EBCDIC here - return new Object [] {"CP037", null}; + return EncodingInfo.EBCDIC; } - return defaultEncoding; + // default encoding + return EncodingInfo.UTF_8; } // getEncodingName(byte[],int):Object[] @@ -2517,95 +2512,95 @@ * encoding name may be a Java encoding name; * otherwise, it is an ianaEncoding name. * @param isBigEndian For encodings (like uCS-4), whose names cannot - * specify a byte order, this tells whether the order is bigEndian. null menas - * unknown or not relevant. + * specify a byte order, this tells whether the order + * is bigEndian. null if unknown or irrelevant. * * @return Returns a reader. */ protected Reader createReader(InputStream inputStream, String encoding, Boolean isBigEndian) - throws IOException { - - // normalize encoding name - if (encoding == null) { - encoding = "UTF-8"; - } - - // try to use an optimized reader - String ENCODING = encoding.toUpperCase(Locale.ENGLISH); - if (ENCODING.equals("UTF-8")) { - if (DEBUG_ENCODINGS) { - System.out.println("$$$ creating UTF8Reader"); - } - return new UTF8Reader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale() ); - } - if (ENCODING.equals("US-ASCII")) { - if (DEBUG_ENCODINGS) { - System.out.println("$$$ creating ASCIIReader"); - } - return new ASCIIReader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale()); - } - if(ENCODING.equals("ISO-10646-UCS-4")) { - if(isBigEndian != null) { - boolean isBE = isBigEndian.booleanValue(); - if(isBE) { - return new UCSReader(inputStream, UCSReader.UCS4BE); + throws IOException { + + String enc = (encoding != null) ? encoding : EncodingInfo.STR_UTF8; + enc = enc.toUpperCase(Locale.ENGLISH); + MessageFormatter f = fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN); + Locale l = fErrorReporter.getLocale(); + switch (enc) { + case EncodingInfo.STR_UTF8: + return new UTF8Reader(inputStream, fBufferSize, f, l); + case EncodingInfo.STR_UTF16: + if (isBigEndian != null) { + return new UTF16Reader(inputStream, fBufferSize, isBigEndian, f, l); + } + break; + case EncodingInfo.STR_UTF16BE: + return new UTF16Reader(inputStream, fBufferSize, true, f, l); + case EncodingInfo.STR_UTF16LE: + return new UTF16Reader(inputStream, fBufferSize, false, f, l); + case EncodingInfo.STR_UCS4: + if(isBigEndian != null) { + if(isBigEndian) { + return new UCSReader(inputStream, UCSReader.UCS4BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS4LE); + } } else { - return new UCSReader(inputStream, UCSReader.UCS4LE); + fErrorReporter.reportError(this.getEntityScanner(), + XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); } - } else { - fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, - "EncodingByteOrderUnsupported", - new Object[] { encoding }, - XMLErrorReporter.SEVERITY_FATAL_ERROR); - } - } - if(ENCODING.equals("ISO-10646-UCS-2")) { - if(isBigEndian != null) { // sould never happen with this encoding... - boolean isBE = isBigEndian.booleanValue(); - if(isBE) { - return new UCSReader(inputStream, UCSReader.UCS2BE); + break; + case EncodingInfo.STR_UCS2: + if(isBigEndian != null) { + if(isBigEndian) { + return new UCSReader(inputStream, UCSReader.UCS2BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS2LE); + } } else { - return new UCSReader(inputStream, UCSReader.UCS2LE); + fErrorReporter.reportError(this.getEntityScanner(), + XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); } - } else { - fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, - "EncodingByteOrderUnsupported", - new Object[] { encoding }, - XMLErrorReporter.SEVERITY_FATAL_ERROR); - } + break; } // check for valid name boolean validIANA = XMLChar.isValidIANAEncoding(encoding); boolean validJava = XMLChar.isValidJavaEncoding(encoding); if (!validIANA || (fAllowJavaEncodings && !validJava)) { - fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, + fErrorReporter.reportError(this.getEntityScanner(), + XMLMessageFormatter.XML_DOMAIN, "EncodingDeclInvalid", new Object[] { encoding }, XMLErrorReporter.SEVERITY_FATAL_ERROR); - // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 - // because every byte is a valid ISO Latin 1 character. - // It may not translate correctly but if we failed on - // the encoding anyway, then we're expecting the content - // of the document to be bad. This will just prevent an - // invalid UTF-8 sequence to be detected. This is only - // important when continue-after-fatal-error is turned - // on. -Ac + // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 + // because every byte is a valid ISO Latin 1 character. + // It may not translate correctly but if we failed on + // the encoding anyway, then we're expecting the content + // of the document to be bad. This will just prevent an + // invalid UTF-8 sequence to be detected. This is only + // important when continue-after-fatal-error is turned + // on. -Ac encoding = "ISO-8859-1"; } // try to use a Java reader - String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); + String javaEncoding = EncodingMap.getIANA2JavaMapping(enc); if (javaEncoding == null) { - if(fAllowJavaEncodings) { + if (fAllowJavaEncodings) { javaEncoding = encoding; } else { - fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, + fErrorReporter.reportError(this.getEntityScanner(), + XMLMessageFormatter.XML_DOMAIN, "EncodingDeclInvalid", new Object[] { encoding }, XMLErrorReporter.SEVERITY_FATAL_ERROR); - // see comment above. - javaEncoding = "ISO8859_1"; + // see comment above. + javaEncoding = "ISO8859_1"; } } if (DEBUG_ENCODINGS) { @@ -2898,108 +2893,78 @@ } // print() /** - * Buffer used in entity manager to reuse character arrays instead - * of creating new ones every time. - * - * @xerces.internal - * - * @author Ankit Pasricha, IBM - */ - private static class CharacterBuffer { - - /** character buffer */ - private char[] ch; - - /** whether the buffer is for an external or internal scanned entity */ - private boolean isExternal; - - public CharacterBuffer(boolean isExternal, int size) { - this.isExternal = isExternal; - ch = new char[size]; - } - } - - - /** - * Stores a number of character buffers and provides it to the entity - * manager to use when an entity is seen. + * Information about auto-detectable encodings. * * @xerces.internal * - * @author Ankit Pasricha, IBM + * @author Michael Glavassevich, IBM */ - private static class CharacterBufferPool { - - private static final int DEFAULT_POOL_SIZE = 3; - - private CharacterBuffer[] fInternalBufferPool; - private CharacterBuffer[] fExternalBufferPool; - - private int fExternalBufferSize; - private int fInternalBufferSize; - private int poolSize; - - private int fInternalTop; - private int fExternalTop; - - public CharacterBufferPool(int externalBufferSize, int internalBufferSize) { - this(DEFAULT_POOL_SIZE, externalBufferSize, internalBufferSize); - } - - public CharacterBufferPool(int poolSize, int externalBufferSize, int internalBufferSize) { - fExternalBufferSize = externalBufferSize; - fInternalBufferSize = internalBufferSize; - this.poolSize = poolSize; - init(); - } - - /** Initializes buffer pool. **/ - private void init() { - fInternalBufferPool = new CharacterBuffer[poolSize]; - fExternalBufferPool = new CharacterBuffer[poolSize]; - fInternalTop = -1; - fExternalTop = -1; - } - - /** Retrieves buffer from pool. **/ - public CharacterBuffer getBuffer(boolean external) { - if (external) { - if (fExternalTop > -1) { - return fExternalBufferPool[fExternalTop--]; - } - else { - return new CharacterBuffer(true, fExternalBufferSize); - } - } - else { - if (fInternalTop > -1) { - return fInternalBufferPool[fInternalTop--]; - } - else { - return new CharacterBuffer(false, fInternalBufferSize); - } - } - } - - /** Returns buffer to pool. **/ - public void returnToPool(CharacterBuffer buffer) { - if (buffer.isExternal) { - if (fExternalTop < fExternalBufferPool.length - 1) { - fExternalBufferPool[++fExternalTop] = buffer; - } - } - else if (fInternalTop < fInternalBufferPool.length - 1) { - fInternalBufferPool[++fInternalTop] = buffer; - } - } - - /** Sets the size of external buffers and dumps the old pool. **/ - public void setExternalBufferSize(int bufferSize) { - fExternalBufferSize = bufferSize; - fExternalBufferPool = new CharacterBuffer[poolSize]; - fExternalTop = -1; - } - } + private static class EncodingInfo { + public static final String STR_UTF8 = "UTF-8"; + public static final String STR_UTF16 = "UTF-16"; + public static final String STR_UTF16BE = "UTF-16BE"; + public static final String STR_UTF16LE = "UTF-16LE"; + public static final String STR_UCS4 = "ISO-10646-UCS-4"; + public static final String STR_UCS2 = "ISO-10646-UCS-2"; + public static final String STR_CP037 = "CP037"; + + /** UTF-8 **/ + public static final EncodingInfo UTF_8 = + new EncodingInfo(STR_UTF8, null, false); + + /** UTF-8, with BOM **/ + public static final EncodingInfo UTF_8_WITH_BOM = + new EncodingInfo(STR_UTF8, null, true); + + /** UTF-16, big-endian **/ + public static final EncodingInfo UTF_16_BIG_ENDIAN = + new EncodingInfo(STR_UTF16BE, STR_UTF16, Boolean.TRUE, false); + + /** UTF-16, big-endian with BOM **/ + public static final EncodingInfo UTF_16_BIG_ENDIAN_WITH_BOM = + new EncodingInfo(STR_UTF16BE, STR_UTF16, Boolean.TRUE, true); + + /** UTF-16, little-endian **/ + public static final EncodingInfo UTF_16_LITTLE_ENDIAN = + new EncodingInfo(STR_UTF16LE, STR_UTF16, Boolean.FALSE, false); + + /** UTF-16, little-endian with BOM **/ + public static final EncodingInfo UTF_16_LITTLE_ENDIAN_WITH_BOM = + new EncodingInfo(STR_UTF16LE, STR_UTF16, Boolean.FALSE, true); + + /** UCS-4, big-endian **/ + public static final EncodingInfo UCS_4_BIG_ENDIAN = + new EncodingInfo(STR_UCS4, Boolean.TRUE, false); + + /** UCS-4, little-endian **/ + public static final EncodingInfo UCS_4_LITTLE_ENDIAN = + new EncodingInfo(STR_UCS4, Boolean.FALSE, false); + + /** UCS-4, unusual byte-order (2143) or (3412) **/ + public static final EncodingInfo UCS_4_UNUSUAL_BYTE_ORDER = + new EncodingInfo(STR_UCS4, null, false); + + /** EBCDIC **/ + public static final EncodingInfo EBCDIC = new EncodingInfo(STR_CP037, null, false); + + public final String autoDetectedEncoding; + public final String readerEncoding; + public final Boolean isBigEndian; + public final boolean hasBOM; + + private EncodingInfo(String autoDetectedEncoding, Boolean isBigEndian, boolean hasBOM) { + this(autoDetectedEncoding, autoDetectedEncoding, isBigEndian, hasBOM); + } // (String,Boolean,boolean) + + private EncodingInfo(String autoDetectedEncoding, String readerEncoding, + Boolean isBigEndian, boolean hasBOM) { + this.autoDetectedEncoding = autoDetectedEncoding; + this.readerEncoding = readerEncoding; + this.isBigEndian = isBigEndian; + this.hasBOM = hasBOM; + } // (String,String,Boolean,boolean) + + } // class EncodingInfo /** * This class wraps the byte inputstreams we're presented with. @@ -3052,20 +3017,13 @@ fOffset = fStartOffset; } - public int read() throws IOException { - int b = 0; - if (fOffset < fLength) { - return fData[fOffset++] & 0xff; - } - if (fOffset == fEndOffset) { - return -1; - } + public int readAndBuffer() throws IOException { if (fOffset == fData.length) { byte[] newData = new byte[fOffset << 1]; System.arraycopy(fData, 0, newData, 0, fOffset); fData = newData; } - b = fInputStream.read(); + final int b = fInputStream.read(); if (b == -1) { fEndOffset = fOffset; return -1; @@ -3075,18 +3033,27 @@ return b & 0xff; } + public int read() throws IOException { + if (fOffset < fLength) { + return fData[fOffset++] & 0xff; + } + if (fOffset == fEndOffset) { + return -1; + } + if (fCurrentEntity.mayReadChunks) { + return fInputStream.read(); + } + return readAndBuffer(); + } + public int read(byte[] b, int off, int len) throws IOException { - int bytesLeft = fLength - fOffset; + final int bytesLeft = fLength - fOffset; if (bytesLeft == 0) { if (fOffset == fEndOffset) { return -1; } - /** - * //System.out.println("fCurrentEntitty = " + fCurrentEntity ); - * //System.out.println("fInputStream = " + fInputStream ); - * // better get some more for the voracious reader... */ - + // read a block of data as requested if(fCurrentEntity.mayReadChunks || !fCurrentEntity.xmlDeclChunkRead) { if (!fCurrentEntity.xmlDeclChunkRead) @@ -3096,15 +3063,13 @@ } return fInputStream.read(b, off, len); } - - int returnedVal = read(); - if(returnedVal == -1) { - fEndOffset = fOffset; - return -1; + int returnedVal = readAndBuffer(); + if (returnedVal == -1) { + fEndOffset = fOffset; + return -1; } b[off] = (byte)returnedVal; return 1; - } if (len < bytesLeft) { if (len <= 0) { @@ -3120,8 +3085,7 @@ return len; } - public long skip(long n) - throws IOException { + public long skip(long n) throws IOException { int bytesLeft; if (n <= 0) { return 0; @@ -3142,7 +3106,7 @@ return bytesLeft; } n -= bytesLeft; - /* + /* * In a manner of speaking, when this class isn't permitting more * than one byte at a time to be read, it is "blocking". The * available() method should indicate how much can be read without @@ -3154,13 +3118,13 @@ } public int available() throws IOException { - int bytesLeft = fLength - fOffset; + final int bytesLeft = fLength - fOffset; if (bytesLeft == 0) { if (fOffset == fEndOffset) { return -1; } return fCurrentEntity.mayReadChunks ? fInputStream.available() - : 0; + : 0; } return bytesLeft; } @@ -3171,7 +3135,6 @@ public void reset() { fOffset = fMark; - //test(); } public boolean markSupported() { diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Fri Apr 19 08:00:42 2019 -0400 @@ -55,6 +55,7 @@ import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.jvm.*; +import com.sun.tools.javac.jvm.PoolConstant; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.Tag; @@ -91,7 +92,7 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -public abstract class Symbol extends AnnoConstruct implements Element { +public abstract class Symbol extends AnnoConstruct implements PoolConstant, Element { /** The kind of this symbol. * @see Kinds @@ -286,6 +287,11 @@ this.name = name; } + @Override + public int poolTag() { + throw new AssertionError("Invalid pool entry"); + } + /** Clone this symbol with new owner. * Legal only for fields and methods. */ @@ -971,6 +977,11 @@ this.type = new ModuleType(this); } + @Override + public int poolTag() { + return ClassFile.CONSTANT_Module; + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) public Name getSimpleName() { return Convert.shortName(name); @@ -1137,6 +1148,11 @@ return members_field; } + @Override + public int poolTag() { + return ClassFile.CONSTANT_Package; + } + public long flags() { complete(); return flags_field; @@ -1237,10 +1253,6 @@ */ public List trans_local; - /** the constant pool of the class - */ - public Pool pool; - /** the annotation metadata attached to this class */ private AnnotationTypeMetadata annotationTypeMetadata; @@ -1251,7 +1263,6 @@ this.flatname = formFlatName(name, owner); this.sourcefile = null; this.classfile = null; - this.pool = null; this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType(); } @@ -1543,6 +1554,11 @@ super(VAR, flags, name, type, owner); } + @Override + public int poolTag() { + return ClassFile.CONSTANT_Fieldref; + } + /** Clone this symbol with new owner. */ public VarSymbol clone(Symbol newOwner) { @@ -1551,6 +1567,11 @@ public Symbol baseSymbol() { return VarSymbol.this; } + + @Override + public Object poolKey(Types types) { + return new Pair<>(newOwner, baseSymbol()); + } }; v.pos = pos; v.adr = adr; @@ -1711,6 +1732,11 @@ public Symbol baseSymbol() { return MethodSymbol.this; } + + @Override + public Object poolKey(Types types) { + return new Pair<>(newOwner, baseSymbol()); + } }; m.code = code; return m; @@ -1740,10 +1766,25 @@ } } + @Override + public int poolTag() { + return owner.isInterface() ? + ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref; + } + public boolean isDynamic() { return false; } + public boolean isHandle() { + return false; + } + + + public MethodHandleSymbol asHandle() { + return new MethodHandleSymbol(this); + } + /** find a symbol that this (proxy method) symbol implements. * @param c The class whose members are searched for * implementations @@ -2027,16 +2068,14 @@ /** A class for invokedynamic method calls. */ - public static class DynamicMethodSymbol extends MethodSymbol { + public static class DynamicMethodSymbol extends MethodSymbol implements Dynamic { - public Object[] staticArgs; - public Symbol bsm; - public int bsmKind; + public LoadableConstant[] staticArgs; + public MethodHandleSymbol bsm; - public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) { + public DynamicMethodSymbol(Name name, Symbol owner, MethodHandleSymbol bsm, Type type, LoadableConstant[] staticArgs) { super(0, name, type, owner); this.bsm = bsm; - this.bsmKind = bsmKind; this.staticArgs = staticArgs; } @@ -2044,6 +2083,83 @@ public boolean isDynamic() { return true; } + + @Override + public LoadableConstant[] staticArgs() { + return staticArgs; + } + + @Override + public MethodHandleSymbol bootstrapMethod() { + return bsm; + } + + @Override + public int poolTag() { + return ClassFile.CONSTANT_InvokeDynamic; + } + + @Override + public Type dynamicType() { + return type; + } + } + + /** A class for method handles. + */ + public static class MethodHandleSymbol extends MethodSymbol implements LoadableConstant { + + private Symbol refSym; + + public MethodHandleSymbol(Symbol msym) { + super(msym.flags_field, msym.name, msym.type, msym.owner); + this.refSym = msym; + } + + /** + * Returns the kind associated with this method handle. + */ + public int referenceKind() { + if (refSym.isConstructor()) { + return ClassFile.REF_newInvokeSpecial; + } else { + if (refSym.isStatic()) { + return ClassFile.REF_invokeStatic; + } else if ((refSym.flags() & PRIVATE) != 0) { + return ClassFile.REF_invokeSpecial; + } else if (refSym.enclClass().isInterface()) { + return ClassFile.REF_invokeInterface; + } else { + return ClassFile.REF_invokeVirtual; + } + } + } + + @Override + public int poolTag() { + return ClassFile.CONSTANT_MethodHandle; + } + + @Override + public Object poolKey(Types types) { + return new Pair<>(baseSymbol(), referenceKind()); + } + + @Override + public MethodHandleSymbol asHandle() { + return this; + } + + @Override + public Symbol baseSymbol() { + return refSym; + } + + + @Override + public boolean isHandle() { + return true; + } } /** A class for predefined operators. diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Fri Apr 19 08:00:42 2019 -0400 @@ -36,7 +36,10 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.TypeMetadata.Entry; import com.sun.tools.javac.code.Types.TypeMapping; +import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Infer.IncorporationAction; +import com.sun.tools.javac.jvm.ClassFile; +import com.sun.tools.javac.jvm.PoolConstant; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; @@ -73,7 +76,7 @@ * * @see TypeTag */ -public abstract class Type extends AnnoConstruct implements TypeMirror { +public abstract class Type extends AnnoConstruct implements TypeMirror, PoolConstant { /** * Type metadata, Should be {@code null} for the default value. @@ -125,6 +128,16 @@ */ public TypeSymbol tsym; + @Override + public int poolTag() { + throw new AssertionError("Invalid pool entry"); + } + + @Override + public Object poolKey(Types types) { + return new UniqueType(this, types); + } + /** * Checks if the current type tag is equal to the given tag. * @return true if tag is equal to the current type tag. @@ -930,7 +943,7 @@ } } - public static class ClassType extends Type implements DeclaredType, + public static class ClassType extends Type implements DeclaredType, LoadableConstant, javax.lang.model.type.ErrorType { /** The enclosing type of this type. If this is the type of an inner @@ -975,6 +988,10 @@ this.interfaces_field = null; } + public int poolTag() { + return ClassFile.CONSTANT_Class; + } + @Override public ClassType cloneWithMetadata(TypeMetadata md) { return new ClassType(outer_field, typarams_field, tsym, md) { @@ -1277,7 +1294,7 @@ } public static class ArrayType extends Type - implements javax.lang.model.type.ArrayType { + implements LoadableConstant, javax.lang.model.type.ArrayType { public Type elemtype; @@ -1297,6 +1314,10 @@ this(that.elemtype, that.tsym, that.getMetadata()); } + public int poolTag() { + return ClassFile.CONSTANT_Class; + } + @Override public ArrayType cloneWithMetadata(TypeMetadata md) { return new ArrayType(elemtype, tsym, md) { @@ -1412,7 +1433,7 @@ } } - public static class MethodType extends Type implements ExecutableType { + public static class MethodType extends Type implements ExecutableType, LoadableConstant { public List argtypes; public Type restype; @@ -1479,6 +1500,11 @@ restype != null && restype.isErroneous(); } + @Override + public int poolTag() { + return ClassFile.CONSTANT_MethodType; + } + public boolean contains(Type elem) { return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem); } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Fri Apr 19 08:00:42 2019 -0400 @@ -48,6 +48,8 @@ import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.comp.LambdaToMethod; +import com.sun.tools.javac.jvm.ClassFile; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.BoundKind.*; @@ -5181,6 +5183,29 @@ } } } + + public Type constantType(LoadableConstant c) { + switch (c.poolTag()) { + case ClassFile.CONSTANT_Class: + return syms.classType; + case ClassFile.CONSTANT_String: + return syms.stringType; + case ClassFile.CONSTANT_Integer: + return syms.intType; + case ClassFile.CONSTANT_Float: + return syms.floatType; + case ClassFile.CONSTANT_Long: + return syms.longType; + case ClassFile.CONSTANT_Double: + return syms.doubleType; + case ClassFile.CONSTANT_MethodHandle: + return syms.methodHandleType; + case ClassFile.CONSTANT_MethodType: + return syms.methodTypeType; + default: + throw new AssertionError("Not a loadable constant: " + c.poolTag()); + } + } // public void newRound() { diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Apr 19 08:00:42 2019 -0400 @@ -25,7 +25,9 @@ package com.sun.tools.javac.comp; +import com.sun.tools.javac.code.Symbol.MethodHandleSymbol; import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.tree.*; @@ -59,7 +61,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -70,13 +71,10 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; -import static com.sun.tools.javac.jvm.Pool.DynamicMethod; import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeKind; -import com.sun.tools.javac.code.Type.IntersectionClassType; -import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError; import com.sun.tools.javac.main.Option; /** @@ -214,7 +212,7 @@ private Map dedupedLambdas; - private Map dynMethSyms = new HashMap<>(); + private Map dynMethSyms = new HashMap<>(); /** * list of deserialization cases @@ -439,11 +437,8 @@ //then, determine the arguments to the indy call List indy_args = translate(syntheticInits.toList(), localContext.prev); - //build a sam instance using an indy call to the meta-factory - int refKind = referenceKind(sym); - //convert to an invokedynamic call - result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); + result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args); } // where @@ -488,7 +483,7 @@ //first determine the method symbol to be used to generate the sam instance //this is either the method reference symbol, or the bridged reference symbol - Symbol refSym = tree.sym; + MethodSymbol refSym = (MethodSymbol)tree.sym; //the qualifying expression is treated as a special captured arg JCExpression init; @@ -522,7 +517,7 @@ //build a sam instance using an indy call to the meta-factory - result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); + result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args); } /** @@ -765,8 +760,8 @@ rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil())); } - private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, - DiagnosticPosition pos, List staticArgs, MethodType indyType) { + private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym, + DiagnosticPosition pos, List staticArgs, MethodType indyType) { String functionalInterfaceClass = classSig(targetType); String functionalInterfaceMethodName = samSym.getSimpleName().toString(); String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); @@ -774,7 +769,8 @@ String implMethodName = refSym.getQualifiedName().toString(); String implMethodSignature = typeSig(types.erasure(refSym.type)); - JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); + JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), + make.Literal(refSym.referenceKind())); ListBuffer serArgs = new ListBuffer<>(); int i = 0; for (Type t : indyType.getParameterTypes()) { @@ -1106,13 +1102,13 @@ * Generate an indy method call to the meta factory */ private JCExpression makeMetafactoryIndyCall(TranslationContext context, - int refKind, Symbol refSym, List indy_args) { + MethodHandleSymbol refSym, List indy_args) { JCFunctionalExpression tree = context.tree; //determine the static bsm args MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym); - List staticArgs = List.of( + List staticArgs = List.of( typeToMethodType(samSym.type), - new Pool.MethodHandle(refKind, refSym, types), + ((MethodSymbol)refSym).asHandle(), typeToMethodType(tree.getDescriptorType(types))); //computed indy arg types @@ -1131,7 +1127,7 @@ names.altMetafactory : names.metafactory; if (context.needsAltMetafactory()) { - ListBuffer markers = new ListBuffer<>(); + ListBuffer markers = new ListBuffer<>(); List targets = tree.target.isIntersection() ? types.directSupertypes(tree.target) : List.nil(); @@ -1140,7 +1136,7 @@ if (t.tsym != syms.serializableType.tsym && t.tsym != tree.type.tsym && t.tsym != syms.objectType.tsym) { - markers.append(t.tsym); + markers.append(t); } } int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; @@ -1152,17 +1148,17 @@ if (hasBridges) { flags |= FLAG_BRIDGES; } - staticArgs = staticArgs.append(flags); + staticArgs = staticArgs.append(LoadableConstant.Int(flags)); if (hasMarkers) { - staticArgs = staticArgs.append(markers.length()); - staticArgs = staticArgs.appendList(markers.toList()); + staticArgs = staticArgs.append(LoadableConstant.Int(markers.length())); + staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList())); } if (hasBridges) { - staticArgs = staticArgs.append(context.bridges.length() - 1); + staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1)); for (Symbol s : context.bridges) { Type s_erasure = s.erasure(types); if (!types.isSameType(s_erasure, samSym.erasure(types))) { - staticArgs = staticArgs.append(s.erasure(types)); + staticArgs = staticArgs.append(((MethodType)s.erasure(types))); } } } @@ -1170,7 +1166,7 @@ int prevPos = make.pos; try { make.at(kInfo.clazz); - addDeserializationCase(refKind, refSym, tree.type, samSym, + addDeserializationCase(refSym, tree.type, samSym, tree, staticArgs, indyType); } finally { make.at(prevPos); @@ -1186,14 +1182,14 @@ * arguments types */ private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, - List staticArgs, MethodType indyType, List indyArgs, - Name methName) { + List staticArgs, MethodType indyType, List indyArgs, + Name methName) { int prevPos = make.pos; try { make.at(pos); List bsm_staticArgs = List.of(syms.methodHandleLookupType, - syms.stringType, - syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); + syms.stringType, + syms.methodTypeType).appendList(staticArgs.map(types::constantType)); Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, bsmName, bsm_staticArgs, List.nil()); @@ -1201,15 +1197,12 @@ DynamicMethodSymbol dynSym = new DynamicMethodSymbol(methName, syms.noSymbol, - bsm.isStatic() ? - ClassFile.REF_invokeStatic : - ClassFile.REF_invokeVirtual, - (MethodSymbol)bsm, + ((MethodSymbol)bsm).asHandle(), indyType, - staticArgs.toArray()); + staticArgs.toArray(new LoadableConstant[staticArgs.length()])); JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent( - new DynamicMethod(dynSym, types), dynSym); + dynSym.poolKey(types), dynSym); qualifier.sym = existing != null ? existing : dynSym; qualifier.type = indyType.getReturnType(); @@ -1220,57 +1213,6 @@ make.at(prevPos); } } - //where - private List bsmStaticArgToTypes(List args) { - ListBuffer argtypes = new ListBuffer<>(); - for (Object arg : args) { - argtypes.append(bsmStaticArgToType(arg)); - } - return argtypes.toList(); - } - - private Type bsmStaticArgToType(Object arg) { - Assert.checkNonNull(arg); - if (arg instanceof ClassSymbol) { - return syms.classType; - } else if (arg instanceof Integer) { - return syms.intType; - } else if (arg instanceof Long) { - return syms.longType; - } else if (arg instanceof Float) { - return syms.floatType; - } else if (arg instanceof Double) { - return syms.doubleType; - } else if (arg instanceof String) { - return syms.stringType; - } else if (arg instanceof Pool.MethodHandle) { - return syms.methodHandleType; - } else if (arg instanceof MethodType) { - return syms.methodTypeType; - } else { - Assert.error("bad static arg " + arg.getClass()); - return null; - } - } - - /** - * Get the opcode associated with this method reference - */ - private int referenceKind(Symbol refSym) { - if (refSym.isConstructor()) { - return ClassFile.REF_newInvokeSpecial; - } else { - if (refSym.isStatic()) { - return ClassFile.REF_invokeStatic; - } else if ((refSym.flags() & PRIVATE) != 0) { - return ClassFile.REF_invokeSpecial; - } else if (refSym.enclClass().isInterface()) { - return ClassFile.REF_invokeInterface; - } else { - return ClassFile.REF_invokeVirtual; - } - } - } // /** @@ -2312,13 +2254,6 @@ this.isSuper = tree.hasKind(ReferenceKind.SUPER); } - /** - * Get the opcode associated with this method reference - */ - int referenceKind() { - return LambdaToMethod.this.referenceKind(tree.sym); - } - boolean needsVarArgsConversion() { return tree.varargsElement != null; } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Fri Apr 19 08:00:42 2019 -0400 @@ -93,7 +93,6 @@ private final Attr attr; private TreeMaker make; private DiagnosticPosition make_pos; - private final ClassWriter writer; private final ConstFold cfolder; private final Target target; private final Source source; @@ -116,7 +115,6 @@ chk = Check.instance(context); attr = Attr.instance(context); make = TreeMaker.instance(context); - writer = ClassWriter.instance(context); cfolder = ConstFold.instance(context); target = Target.instance(context); source = Source.instance(context); @@ -475,7 +473,7 @@ .fromString(target.syntheticNameChar() + "SwitchMap" + target.syntheticNameChar() + - writer.xClassName(forEnum.type).toString() + names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString() .replace('/', '.') .replace('.', target.syntheticNameChar())); ClassSymbol outerCacheClass = outerCacheClass(); diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java Fri Apr 19 08:00:42 2019 -0400 @@ -25,9 +25,6 @@ package com.sun.tools.javac.jvm; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.util.Name; @@ -189,38 +186,4 @@ public static byte[] externalize(Name name) { return externalize(name.getByteArray(), name.getByteOffset(), name.getByteLength()); } - -/************************************************************************ - * Name-and-type - ***********************************************************************/ - - /** A class for the name-and-type signature of a method or field. - */ - public static class NameAndType { - Name name; - UniqueType uniqueType; - Types types; - - NameAndType(Name name, Type type, Types types) { - this.name = name; - this.uniqueType = new UniqueType(type, types); - this.types = types; - } - - void setType(Type type) { - this.uniqueType = new UniqueType(type, types); - } - - @Override - public boolean equals(Object other) { - return (other instanceof NameAndType && - name == ((NameAndType) other).name && - uniqueType.equals(((NameAndType) other).uniqueType)); - } - - @Override - public int hashCode() { - return name.hashCode() * uniqueType.hashCode(); - } - } } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.IntFunction; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; @@ -55,8 +56,8 @@ import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.PathFileObject; -import com.sun.tools.javac.jvm.ClassFile.NameAndType; import com.sun.tools.javac.jvm.ClassFile.Version; +import com.sun.tools.javac.jvm.PoolConstant.NameAndType; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Warnings; @@ -100,11 +101,6 @@ */ boolean verbose; - /** Switch: read constant pool and code sections. This switch is initially - * set to false but can be turned on from outside. - */ - public boolean readAllOfClassFile = false; - /** Switch: allow modules. */ boolean allowModules; @@ -170,20 +166,15 @@ /** The buffer containing the currently read class file. */ - byte[] buf = new byte[INITIAL_BUFFER_SIZE]; + ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE); /** The current input pointer. */ protected int bp; - /** The objects of the constant pool. + /** The pool reader. */ - Object[] poolObj; - - /** For every constant pool entry, an index into buf where the - * defining section of the entry is found. - */ - int[] poolIdx; + PoolReader poolReader; /** The major version number of the class file being read. */ int majorVersion; @@ -323,294 +314,29 @@ /** Read a character. */ char nextChar() { - return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); + char res = buf.getChar(bp); + bp += 2; + return res; } /** Read a byte. */ int nextByte() { - return buf[bp++] & 0xFF; + return buf.getByte(bp++) & 0xFF; } /** Read an integer. */ int nextInt() { - return - ((buf[bp++] & 0xFF) << 24) + - ((buf[bp++] & 0xFF) << 16) + - ((buf[bp++] & 0xFF) << 8) + - (buf[bp++] & 0xFF); - } - - /** Extract a character at position bp from buf. - */ - char getChar(int bp) { - return - (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF)); - } - - /** Extract an integer at position bp from buf. - */ - int getInt(int bp) { - return - ((buf[bp] & 0xFF) << 24) + - ((buf[bp+1] & 0xFF) << 16) + - ((buf[bp+2] & 0xFF) << 8) + - (buf[bp+3] & 0xFF); - } - - - /** Extract a long integer at position bp from buf. - */ - long getLong(int bp) { - DataInputStream bufin = - new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); - try { - return bufin.readLong(); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - /** Extract a float at position bp from buf. - */ - float getFloat(int bp) { - DataInputStream bufin = - new DataInputStream(new ByteArrayInputStream(buf, bp, 4)); - try { - return bufin.readFloat(); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - /** Extract a double at position bp from buf. - */ - double getDouble(int bp) { - DataInputStream bufin = - new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); - try { - return bufin.readDouble(); - } catch (IOException e) { - throw new AssertionError(e); - } + int res = buf.getInt(bp); + bp += 4; + return res; } /************************************************************************ * Constant Pool Access ***********************************************************************/ - /** Index all constant pool entries, writing their start addresses into - * poolIdx. - */ - void indexPool() { - poolIdx = new int[nextChar()]; - poolObj = new Object[poolIdx.length]; - int i = 1; - while (i < poolIdx.length) { - poolIdx[i++] = bp; - byte tag = buf[bp++]; - switch (tag) { - case CONSTANT_Utf8: case CONSTANT_Unicode: { - int len = nextChar(); - bp = bp + len; - break; - } - case CONSTANT_Class: - case CONSTANT_String: - case CONSTANT_MethodType: - case CONSTANT_Module: - case CONSTANT_Package: - bp = bp + 2; - break; - case CONSTANT_MethodHandle: - bp = bp + 3; - break; - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - case CONSTANT_NameandType: - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Dynamic: - case CONSTANT_InvokeDynamic: - bp = bp + 4; - break; - case CONSTANT_Long: - case CONSTANT_Double: - bp = bp + 8; - i++; - break; - default: - throw badClassFile("bad.const.pool.tag.at", - Byte.toString(tag), - Integer.toString(bp -1)); - } - } - } - - /** Read constant pool entry at start address i, use pool as a cache. - */ - Object readPool(int i) { - Object result = poolObj[i]; - if (result != null) return result; - - int index = poolIdx[i]; - if (index == 0) return null; - - byte tag = buf[index]; - switch (tag) { - case CONSTANT_Utf8: - poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1)); - break; - case CONSTANT_Unicode: - throw badClassFile("unicode.str.not.supported"); - case CONSTANT_Class: - poolObj[i] = readClassOrType(getChar(index + 1)); - break; - case CONSTANT_String: - // FIXME: (footprint) do not use toString here - poolObj[i] = readName(getChar(index + 1)).toString(); - break; - case CONSTANT_Fieldref: { - ClassSymbol owner = readClassSymbol(getChar(index + 1)); - NameAndType nt = readNameAndType(getChar(index + 3)); - poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner); - break; - } - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: { - ClassSymbol owner = readClassSymbol(getChar(index + 1)); - NameAndType nt = readNameAndType(getChar(index + 3)); - poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner); - break; - } - case CONSTANT_NameandType: - poolObj[i] = new NameAndType( - readName(getChar(index + 1)), - readType(getChar(index + 3)), types); - break; - case CONSTANT_Integer: - poolObj[i] = getInt(index + 1); - break; - case CONSTANT_Float: - poolObj[i] = Float.valueOf(getFloat(index + 1)); - break; - case CONSTANT_Long: - poolObj[i] = Long.valueOf(getLong(index + 1)); - break; - case CONSTANT_Double: - poolObj[i] = Double.valueOf(getDouble(index + 1)); - break; - case CONSTANT_MethodHandle: - skipBytes(4); - break; - case CONSTANT_MethodType: - skipBytes(3); - break; - case CONSTANT_Dynamic: - case CONSTANT_InvokeDynamic: - skipBytes(5); - break; - case CONSTANT_Module: - case CONSTANT_Package: - // this is temporary for now: treat as a simple reference to the underlying Utf8. - poolObj[i] = readName(getChar(index + 1)); - break; - default: - throw badClassFile("bad.const.pool.tag", Byte.toString(tag)); - } - return poolObj[i]; - } - - /** Read signature and convert to type. - */ - Type readType(int i) { - int index = poolIdx[i]; - return sigToType(buf, index + 3, getChar(index + 1)); - } - - /** If name is an array type or class signature, return the - * corresponding type; otherwise return a ClassSymbol with given name. - */ - Object readClassOrType(int i) { - int index = poolIdx[i]; - int len = getChar(index + 1); - int start = index + 3; - Assert.check(buf[start] == '[' || buf[start + len - 1] != ';'); - // by the above assertion, the following test can be - // simplified to (buf[start] == '[') - return (buf[start] == '[' || buf[start + len - 1] == ';') - ? (Object)sigToType(buf, start, len) - : (Object)enterClass(names.fromUtf(internalize(buf, start, - len))); - } - - /** Read signature and convert to type parameters. - */ - List readTypeParams(int i) { - int index = poolIdx[i]; - return sigToTypeParams(buf, index + 3, getChar(index + 1)); - } - - /** Read class entry. - */ - ClassSymbol readClassSymbol(int i) { - Object obj = readPool(i); - if (obj != null && !(obj instanceof ClassSymbol)) - throw badClassFile("bad.const.pool.entry", - currentClassFile.toString(), - "CONSTANT_Class_info", i); - return (ClassSymbol)obj; - } - - Name readClassName(int i) { - int index = poolIdx[i]; - if (index == 0) return null; - byte tag = buf[index]; - if (tag != CONSTANT_Class) { - throw badClassFile("bad.const.pool.entry", - currentClassFile.toString(), - "CONSTANT_Class_info", i); - } - int nameIndex = poolIdx[getChar(index + 1)]; - int len = getChar(nameIndex + 1); - int start = nameIndex + 3; - if (buf[start] == '[' || buf[start + len - 1] == ';') - throw badClassFile("wrong class name"); //TODO: proper diagnostics - return names.fromUtf(internalize(buf, start, len)); - } - - /** Read name. - */ - Name readName(int i) { - Object obj = readPool(i); - if (obj != null && !(obj instanceof Name)) - throw badClassFile("bad.const.pool.entry", - currentClassFile.toString(), - "CONSTANT_Utf8_info or CONSTANT_String_info", i); - return (Name)obj; - } - - /** Read name and type. - */ - NameAndType readNameAndType(int i) { - Object obj = readPool(i); - if (obj != null && !(obj instanceof NameAndType)) - throw badClassFile("bad.const.pool.entry", - currentClassFile.toString(), - "CONSTANT_NameAndType_info", i); - return (NameAndType)obj; - } - - /** Read the name of a module. - * The name is stored in a CONSTANT_Module entry, in - * JVMS 4.2 binary form (using ".", not "/") - */ - Name readModuleName(int i) { - return readName(i); - } - /** Read module_flags. */ Set readModuleFlags(int flags) { @@ -762,7 +488,7 @@ List argtypes = sigToTypes(')'); Type restype = sigToType(); List thrown = List.nil(); - while (signature[sigp] == '^') { + while (sigp < siglimit && signature[sigp] == '^') { sigp++; thrown = thrown.prepend(sigToType()); } @@ -855,7 +581,7 @@ }; switch (signature[sigp++]) { case ';': - if (sigp < signature.length && signature[sigp] == '.') { + if (sigp < siglimit && signature[sigp] == '.') { // support old-style GJC signatures // The signature produced was // Lfoo/Outer;.Lfoo/Outer$Inner; @@ -1049,7 +775,7 @@ new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { - if (readAllOfClassFile || saveParameterNames) + if (saveParameterNames) ((MethodSymbol)sym).code = readCode(sym); else bp = bp + attrLen; @@ -1058,7 +784,7 @@ new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { - Object v = readPool(nextChar()); + Object v = poolReader.getConstant(nextChar()); // Ignore ConstantValue attribute if field not final. if ((sym.flags() & FINAL) == 0) { return; @@ -1115,7 +841,7 @@ int nexceptions = nextChar(); List thrown = List.nil(); for (int j = 0; j < nexceptions; j++) - thrown = thrown.prepend(readClassSymbol(nextChar()).type); + thrown = thrown.prepend(poolReader.getClass(nextChar()).type); if (sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown.reverse(); } @@ -1173,7 +899,7 @@ new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { ClassSymbol c = (ClassSymbol) sym; - Name n = readName(nextChar()); + Name n = poolReader.getName(nextChar()); c.sourcefile = new SourceFileObject(n); // If the class is a toplevel class, originating from a Java source file, // but the class name does not match the file name, then it is @@ -1211,7 +937,8 @@ try { ClassType ct1 = (ClassType)c.type; Assert.check(c == currentOwner); - ct1.typarams_field = readTypeParams(nextChar()); + ct1.typarams_field = poolReader.getName(nextChar()) + .map(ClassReader.this::sigToTypeParams); ct1.supertype_field = sigToType(); ListBuffer is = new ListBuffer<>(); while (sigp != siglimit) is.append(sigToType()); @@ -1221,7 +948,7 @@ } } else { List thrown = sym.type.getThrownTypes(); - sym.type = readType(nextChar()); + sym.type = poolReader.getType(nextChar()); //- System.err.println(" # " + sym.type); if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) sym.type.asMethodType().thrown = thrown; @@ -1342,19 +1069,19 @@ ModuleSymbol msym = (ModuleSymbol) sym.owner; ListBuffer directives = new ListBuffer<>(); - Name moduleName = readModuleName(nextChar()); + Name moduleName = poolReader.peekModuleName(nextChar(), names::fromUtf); if (currentModule.name != moduleName) { throw badClassFile("module.name.mismatch", moduleName, currentModule.name); } Set moduleFlags = readModuleFlags(nextChar()); msym.flags.addAll(moduleFlags); - msym.version = readName(nextChar()); + msym.version = optPoolEntry(nextChar(), poolReader::getName, null); ListBuffer requires = new ListBuffer<>(); int nrequires = nextChar(); for (int i = 0; i < nrequires; i++) { - ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar())); + ModuleSymbol rsym = poolReader.getModule(nextChar()); Set flags = readRequiresFlags(nextChar()); if (rsym == syms.java_base && majorVersion >= V54.major) { if (flags.contains(RequiresFlag.TRANSITIVE)) { @@ -1373,8 +1100,7 @@ ListBuffer exports = new ListBuffer<>(); int nexports = nextChar(); for (int i = 0; i < nexports; i++) { - Name n = readName(nextChar()); - PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n))); + PackageSymbol p = poolReader.getPackage(nextChar()); Set flags = readExportsFlags(nextChar()); int nto = nextChar(); List to; @@ -1383,7 +1109,7 @@ } else { ListBuffer lb = new ListBuffer<>(); for (int t = 0; t < nto; t++) - lb.append(syms.enterModule(readModuleName(nextChar()))); + lb.append(poolReader.getModule(nextChar())); to = lb.toList(); } exports.add(new ExportsDirective(p, to, flags)); @@ -1396,8 +1122,7 @@ throw badClassFile("module.non.zero.opens", currentModule.name); } for (int i = 0; i < nopens; i++) { - Name n = readName(nextChar()); - PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n))); + PackageSymbol p = poolReader.getPackage(nextChar()); Set flags = readOpensFlags(nextChar()); int nto = nextChar(); List to; @@ -1406,7 +1131,7 @@ } else { ListBuffer lb = new ListBuffer<>(); for (int t = 0; t < nto; t++) - lb.append(syms.enterModule(readModuleName(nextChar()))); + lb.append(poolReader.getModule(nextChar())); to = lb.toList(); } opens.add(new OpensDirective(p, to, flags)); @@ -1419,7 +1144,7 @@ ListBuffer uses = new ListBuffer<>(); int nuses = nextChar(); for (int i = 0; i < nuses; i++) { - Name srvc = readClassName(nextChar()); + Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper); uses.add(new InterimUsesDirective(srvc)); } interimUses = uses.toList(); @@ -1427,17 +1152,21 @@ ListBuffer provides = new ListBuffer<>(); int nprovides = nextChar(); for (int p = 0; p < nprovides; p++) { - Name srvc = readClassName(nextChar()); + Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper); int nimpls = nextChar(); ListBuffer impls = new ListBuffer<>(); for (int i = 0; i < nimpls; i++) { - impls.append(readClassName(nextChar())); + impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper)); provides.add(new InterimProvidesDirective(srvc, impls.toList())); } } interimProvides = provides.toList(); } } + + private Name classNameMapper(byte[] arr, int offset, int length) { + return names.fromUtf(ClassFile.internalize(arr, offset, length)); + } }, new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) { @@ -1464,8 +1193,8 @@ // the scope specified by the attribute sym.owner.members().remove(sym); ClassSymbol self = (ClassSymbol)sym; - ClassSymbol c = readClassSymbol(nextChar()); - NameAndType nt = readNameAndType(nextChar()); + ClassSymbol c = poolReader.getClass(nextChar()); + NameAndType nt = optPoolEntry(nextChar(), poolReader::getNameAndType, null); if (c.members_field == null || c.kind != TYP) throw badClassFile("bad.enclosing.class", self, c); @@ -1520,7 +1249,7 @@ if (nt == null) return null; - MethodType type = nt.uniqueType.type.asMethodType(); + MethodType type = nt.type.asMethodType(); for (Symbol sym : scope.getSymbolsByName(nt.name)) { if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type)) @@ -1533,15 +1262,15 @@ if ((flags & INTERFACE) != 0) // no enclosing instance return null; - if (nt.uniqueType.type.getParameterTypes().isEmpty()) + if (nt.type.getParameterTypes().isEmpty()) // no parameters return null; // A constructor of an inner class. // Remove the first argument (the enclosing instance) - nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail, - nt.uniqueType.type.getReturnType(), - nt.uniqueType.type.getThrownTypes(), + nt = new NameAndType(nt.name, new MethodType(nt.type.getParameterTypes().tail, + nt.type.getReturnType(), + nt.type.getThrownTypes(), syms.methodClass)); // Try searching again return findMethod(nt, scope, flags); @@ -1578,7 +1307,7 @@ void readAttrs(Symbol sym, AttributeKind kind) { char ac = nextChar(); for (int i = 0; i < ac; i++) { - Name attrName = readName(nextChar()); + Name attrName = poolReader.getName(nextChar()); int attrLen = nextInt(); AttributeReader r = attributeReaders.get(attrName); if (r != null && r.accepts(kind)) @@ -1681,7 +1410,7 @@ /** Read parameter annotations. */ void readParameterAnnotations(Symbol meth) { - int numParameters = buf[bp++] & 0xFF; + int numParameters = buf.getByte(bp++) & 0xFF; if (parameterAnnotations == null) { parameterAnnotations = new ParameterAnnotations[numParameters]; } else if (parameterAnnotations.length != numParameters) { @@ -1725,39 +1454,30 @@ Type readTypeOrClassSymbol(int i) { // support preliminary jsr175-format class files - if (buf[poolIdx[i]] == CONSTANT_Class) - return readClassSymbol(i).type; - return readTypeToProxy(i); - } - Type readEnumType(int i) { - // support preliminary jsr175-format class files - int index = poolIdx[i]; - int length = getChar(index + 1); - if (buf[index + length + 2] != ';') - return enterClass(readName(i)).type; + if (poolReader.hasTag(i, CONSTANT_Class)) + return poolReader.getClass(i).type; return readTypeToProxy(i); } Type readTypeToProxy(int i) { if (currentModule.module_info == currentOwner) { - int index = poolIdx[i]; - return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1))); + return new ProxyType(i); } else { - return readType(i); + return poolReader.getType(i); } } CompoundAnnotationProxy readCompoundAnnotation() { Type t; if (currentModule.module_info == currentOwner) { - int index = poolIdx[nextChar()]; - t = new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1))); + int cpIndex = nextChar(); + t = new ProxyType(cpIndex); } else { t = readTypeOrClassSymbol(nextChar()); } int numFields = nextChar(); ListBuffer> pairs = new ListBuffer<>(); for (int i=0; i(name, value)); } @@ -1970,29 +1690,40 @@ } + /** + * Helper function to read an optional pool entry (with given function); this is used while parsing + * InnerClasses and EnclosingMethod attributes, as well as when parsing supertype descriptor, + * as per JVMS. + */ + Z optPoolEntry(int index, IntFunction poolFunc, Z defaultValue) { + return (index == 0) ? + defaultValue : + poolFunc.apply(index); + } + Attribute readAttributeValue() { - char c = (char) buf[bp++]; + char c = (char) buf.getByte(bp++); switch (c) { case 'B': - return new Attribute.Constant(syms.byteType, readPool(nextChar())); + return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar())); case 'C': - return new Attribute.Constant(syms.charType, readPool(nextChar())); + return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar())); case 'D': - return new Attribute.Constant(syms.doubleType, readPool(nextChar())); + return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar())); case 'F': - return new Attribute.Constant(syms.floatType, readPool(nextChar())); + return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar())); case 'I': - return new Attribute.Constant(syms.intType, readPool(nextChar())); + return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar())); case 'J': - return new Attribute.Constant(syms.longType, readPool(nextChar())); + return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar())); case 'S': - return new Attribute.Constant(syms.shortType, readPool(nextChar())); + return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar())); case 'Z': - return new Attribute.Constant(syms.booleanType, readPool(nextChar())); + return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar())); case 's': - return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString()); + return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString()); case 'e': - return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar())); + return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar())); case 'c': return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar())); case '[': { @@ -2401,8 +2132,8 @@ */ VarSymbol readField() { long flags = adjustFieldFlags(nextChar()); - Name name = readName(nextChar()); - Type type = readType(nextChar()); + Name name = poolReader.getName(nextChar()); + Type type = poolReader.getType(nextChar()); VarSymbol v = new VarSymbol(flags, name, type, currentOwner); readMemberAttrs(v); return v; @@ -2412,8 +2143,8 @@ */ MethodSymbol readMethod() { long flags = adjustMethodFlags(nextChar()); - Name name = readName(nextChar()); - Type type = readType(nextChar()); + Name name = poolReader.getName(nextChar()); + Type type = poolReader.getType(nextChar()); if (currentOwner.isInterface() && (flags & ABSTRACT) == 0 && !name.equals(names.clinit)) { if (majorVersion > Version.V52.major || @@ -2592,7 +2323,7 @@ Name argName; if (parameterNameIndices != null && index < parameterNameIndices.length && parameterNameIndices[index] != 0) { - argName = readName(parameterNameIndices[index]); + argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty); flags |= NAME_FILLED; } else { String prefix = "arg"; @@ -2681,7 +2412,7 @@ if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags; // read own class name and check that it matches currentModule = c.packge().modle; - ClassSymbol self = readClassSymbol(nextChar()); + ClassSymbol self = poolReader.getClass(nextChar()); if (c != self) { throw badClassFile("class.file.wrong.class", self.flatname); @@ -2710,11 +2441,6 @@ for (int i = 0; i < methodCount; i++) skipMember(); readClassAttrs(c); - if (readAllOfClassFile) { - for (int i = 1; i < poolObj.length; i++) readPool(i); - c.pool = new Pool(poolObj.length, poolObj, types); - } - // reset and read rest of classinfo bp = startbp; int n = nextChar(); @@ -2722,13 +2448,12 @@ throw badClassFile("module.info.invalid.super.class"); } if (ct.supertype_field == null) - ct.supertype_field = (n == 0) - ? Type.noType - : readClassSymbol(n).erasure(types); + ct.supertype_field = + optPoolEntry(n, idx -> poolReader.getClass(idx).erasure(types), Type.noType); n = nextChar(); List is = List.nil(); for (int i = 0; i < n; i++) { - Type _inter = readClassSymbol(nextChar()).erasure(types); + Type _inter = poolReader.getClass(nextChar()).erasure(types); is = is.prepend(_inter); } if (ct.interfaces_field == null) @@ -2749,8 +2474,10 @@ int n = nextChar(); for (int i = 0; i < n; i++) { nextChar(); // skip inner class symbol - ClassSymbol outer = readClassSymbol(nextChar()); - Name name = readName(nextChar()); + int outerIdx = nextChar(); + int nameIdx = nextChar(); + ClassSymbol outer = optPoolEntry(outerIdx, poolReader::getClass, null); + Name name = optPoolEntry(nameIdx, poolReader::getName, names.empty); if (name == null) name = names.empty; long flags = adjustClassFlags(nextChar()); if (outer != null) { // we have a member class @@ -2804,7 +2531,8 @@ } } - indexPool(); + poolReader = new PoolReader(this, names, syms); + bp = poolReader.readPool(buf, bp); if (signatureBuffer.length < bp) { int ns = Integer.highestOneBit(bp) << 1; signatureBuffer = new byte[ns]; @@ -2821,7 +2549,8 @@ repeatable = null; try { bp = 0; - buf = readInputStream(buf, c.classfile.openInputStream()); + buf.reset(); + buf.appendStream(c.classfile.openInputStream()); readClassBuffer(c); if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { List missing = missingTypeVariables; @@ -2875,43 +2604,6 @@ filling = false; } } - // where - private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { - try { - buf = ensureCapacity(buf, s.available()); - int r = s.read(buf); - int bp = 0; - while (r != -1) { - bp += r; - buf = ensureCapacity(buf, bp); - r = s.read(buf, bp, buf.length - bp); - } - return buf; - } finally { - try { - s.close(); - } catch (IOException e) { - /* Ignore any errors, as this stream may have already - * thrown a related exception which is the one that - * should be reported. - */ - } - } - } - /* - * ensureCapacity will increase the buffer as needed, taking note that - * the new buffer will always be greater than the needed and never - * exactly equal to the needed size or bp. If equal then the read (above) - * will infinitely loop as buf.length - bp == 0. - */ - private static byte[] ensureCapacity(byte[] buf, int needed) { - if (buf.length <= needed) { - byte[] old = buf; - buf = new byte[Integer.highestOneBit(needed) << 1]; - System.arraycopy(old, 0, buf, 0, old.length); - } - return buf; - } /** We can only read a single class file at a time; this * flag keeps track of when we are currently reading a class @@ -3098,11 +2790,11 @@ private class ProxyType extends Type { - private final byte[] content; + private final Name name; - public ProxyType(byte[] content) { + public ProxyType(int index) { super(syms.noSymbol, TypeMetadata.EMPTY); - this.content = content; + this.name = poolReader.getName(index); } @Override @@ -3116,7 +2808,7 @@ } public Type resolve() { - return sigToType(content, 0, content.length); + return name.map(ClassReader.this::sigToType); } @Override @DefinedBy(Api.LANGUAGE_MODEL) diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Apr 19 08:00:42 2019 -0400 @@ -29,9 +29,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.stream.Collectors; import javax.tools.JavaFileManager; import javax.tools.FileObject; @@ -44,13 +42,10 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException; -import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.file.PathFileObject; -import com.sun.tools.javac.jvm.Pool.DynamicMethod; -import com.sun.tools.javac.jvm.Pool.Method; -import com.sun.tools.javac.jvm.Pool.MethodHandle; -import com.sun.tools.javac.jvm.Pool.Variable; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; +import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey; import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.util.*; @@ -121,7 +116,7 @@ * Sizes are increased when buffers get full. */ static final int DATA_BUF_SIZE = 0x0fff0; - static final int POOL_BUF_SIZE = 0x1fff0; + static final int CLASS_BUF_SIZE = 0x1fff0; /** An output buffer for member info. */ @@ -129,25 +124,11 @@ /** An output buffer for the constant pool. */ - ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE); - - /** The constant pool. - */ - Pool pool; - - /** The inner classes to be written, as a set. - */ - Set innerClasses; + ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE); - /** The inner classes to be written, as a queue where - * enclosing classes come first. + /** The constant pool writer. */ - ListBuffer innerClassesQueue; - - /** The bootstrap methods to be written in the corresponding class attribute - * (one for each invokedynamic) - */ - Map bootstrapMethods; + final PoolWriter poolWriter; /** The log to use for verbose output. */ @@ -159,9 +140,6 @@ /** Access to files. */ private final JavaFileManager fileManager; - /** Sole signature generator */ - private final CWSignatureGenerator signatureGen; - /** The tags and constants used in compressed stackmap. */ static final int SAME_FRAME_SIZE = 64; static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; @@ -191,7 +169,7 @@ types = Types.instance(context); check = Check.instance(context); fileManager = context.get(JavaFileManager.class); - signatureGen = new CWSignatureGenerator(types); + poolWriter = Gen.instance(context).poolWriter; verbose = options.isSet(VERBOSE); genCrt = options.isSet(XJCOV); @@ -272,108 +250,17 @@ buf.elems[adr+3] = (byte)((x ) & 0xFF); } - /** - * Signature Generation - */ - private class CWSignatureGenerator extends Types.SignatureGenerator { - - /** - * An output buffer for type signatures. - */ - ByteBuffer sigbuf = new ByteBuffer(); - - CWSignatureGenerator(Types types) { - super(types); - } - - /** - * Assemble signature of given type in string buffer. - * Check for uninitialized types before calling the general case. - */ - @Override - public void assembleSig(Type type) { - switch (type.getTag()) { - case UNINITIALIZED_THIS: - case UNINITIALIZED_OBJECT: - // we don't yet have a spec for uninitialized types in the - // local variable table - assembleSig(types.erasure(((UninitializedType)type).qtype)); - break; - default: - super.assembleSig(type); - } - } - - @Override - protected void append(char ch) { - sigbuf.appendByte(ch); - } - - @Override - protected void append(byte[] ba) { - sigbuf.appendBytes(ba); - } - - @Override - protected void append(Name name) { - sigbuf.appendName(name); - } - - @Override - protected void classReference(ClassSymbol c) { - enterInner(c); - } - - private void reset() { - sigbuf.reset(); - } - - private Name toName() { - return sigbuf.toName(names); - } - - private boolean isEmpty() { - return sigbuf.length == 0; - } - } - - /** - * Return signature of given type - */ - Name typeSig(Type type) { - Assert.check(signatureGen.isEmpty()); - //- System.out.println(" ? " + type); - signatureGen.assembleSig(type); - Name n = signatureGen.toName(); - signatureGen.reset(); - //- System.out.println(" " + n); - return n; - } - - /** Given a type t, return the extended class name of its erasure in - * external representation. - */ - public Name xClassName(Type t) { - if (t.hasTag(CLASS)) { - return names.fromUtf(externalize(t.tsym.flatName())); - } else if (t.hasTag(ARRAY)) { - return typeSig(types.erasure(t)); - } else { - throw new AssertionError("xClassName expects class or array type, got " + t); - } - } - /****************************************************************** * Writing the Constant Pool ******************************************************************/ /** Thrown when the constant pool is over full. */ - public static class PoolOverflow extends Exception { + public static class PoolOverflow extends RuntimeException { private static final long serialVersionUID = 0; public PoolOverflow() {} } - public static class StringOverflow extends Exception { + public static class StringOverflow extends RuntimeException { private static final long serialVersionUID = 0; public final String value; public StringOverflow(String s) { @@ -381,137 +268,6 @@ } } - /** Write constant pool to pool buffer. - * Note: during writing, constant pool - * might grow since some parts of constants still need to be entered. - */ - void writePool(Pool pool) throws PoolOverflow, StringOverflow { - int poolCountIdx = poolbuf.length; - poolbuf.appendChar(0); - int i = 1; - while (i < pool.pp) { - Object value = pool.pool[i]; - Assert.checkNonNull(value); - if (value instanceof Method || value instanceof Variable) - value = ((DelegatedSymbol)value).getUnderlyingSymbol(); - - if (value instanceof MethodSymbol) { - MethodSymbol m = (MethodSymbol)value; - if (!m.isDynamic()) { - poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0 - ? CONSTANT_InterfaceMethodref - : CONSTANT_Methodref); - poolbuf.appendChar(pool.put(m.owner)); - poolbuf.appendChar(pool.put(nameType(m))); - } else { - //invokedynamic - DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m; - MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types); - DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types); - - // Figure out the index for existing BSM; create a new BSM if no key - DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key); - if (val == null) { - int index = bootstrapMethods.size(); - val = new DynamicMethod.BootstrapMethodsValue(handle, index); - bootstrapMethods.put(key, val); - } - - //init cp entries - pool.put(names.BootstrapMethods); - pool.put(handle); - for (Object staticArg : dynSym.staticArgs) { - pool.put(staticArg); - } - poolbuf.appendByte(CONSTANT_InvokeDynamic); - poolbuf.appendChar(val.index); - poolbuf.appendChar(pool.put(nameType(dynSym))); - } - } else if (value instanceof VarSymbol) { - VarSymbol v = (VarSymbol)value; - poolbuf.appendByte(CONSTANT_Fieldref); - poolbuf.appendChar(pool.put(v.owner)); - poolbuf.appendChar(pool.put(nameType(v))); - } else if (value instanceof Name) { - poolbuf.appendByte(CONSTANT_Utf8); - byte[] bs = ((Name)value).toUtf(); - poolbuf.appendChar(bs.length); - poolbuf.appendBytes(bs, 0, bs.length); - if (bs.length > Pool.MAX_STRING_LENGTH) - throw new StringOverflow(value.toString()); - } else if (value instanceof ClassSymbol) { - ClassSymbol c = (ClassSymbol)value; - if (c.owner.kind == TYP) pool.put(c.owner); - poolbuf.appendByte(CONSTANT_Class); - if (c.type.hasTag(ARRAY)) { - poolbuf.appendChar(pool.put(typeSig(c.type))); - } else { - poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname)))); - enterInner(c); - } - } else if (value instanceof NameAndType) { - NameAndType nt = (NameAndType)value; - poolbuf.appendByte(CONSTANT_NameandType); - poolbuf.appendChar(pool.put(nt.name)); - poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type))); - } else if (value instanceof Integer) { - poolbuf.appendByte(CONSTANT_Integer); - poolbuf.appendInt(((Integer)value).intValue()); - } else if (value instanceof Long) { - poolbuf.appendByte(CONSTANT_Long); - poolbuf.appendLong(((Long)value).longValue()); - i++; - } else if (value instanceof Float) { - poolbuf.appendByte(CONSTANT_Float); - poolbuf.appendFloat(((Float)value).floatValue()); - } else if (value instanceof Double) { - poolbuf.appendByte(CONSTANT_Double); - poolbuf.appendDouble(((Double)value).doubleValue()); - i++; - } else if (value instanceof String) { - poolbuf.appendByte(CONSTANT_String); - poolbuf.appendChar(pool.put(names.fromString((String)value))); - } else if (value instanceof UniqueType) { - Type type = ((UniqueType)value).type; - if (type.hasTag(METHOD)) { - poolbuf.appendByte(CONSTANT_MethodType); - poolbuf.appendChar(pool.put(typeSig((MethodType)type))); - } else { - Assert.check(type.hasTag(ARRAY)); - poolbuf.appendByte(CONSTANT_Class); - poolbuf.appendChar(pool.put(xClassName(type))); - } - } else if (value instanceof MethodHandle) { - MethodHandle ref = (MethodHandle)value; - poolbuf.appendByte(CONSTANT_MethodHandle); - poolbuf.appendByte(ref.refKind); - poolbuf.appendChar(pool.put(ref.refSym)); - } else if (value instanceof ModuleSymbol) { - ModuleSymbol m = (ModuleSymbol)value; - poolbuf.appendByte(CONSTANT_Module); - poolbuf.appendChar(pool.put(m.name)); - } else if (value instanceof PackageSymbol) { - PackageSymbol m = (PackageSymbol)value; - poolbuf.appendByte(CONSTANT_Package); - poolbuf.appendChar(pool.put(names.fromUtf(externalize(m.fullname)))); - } else { - Assert.error("writePool " + value); - } - i++; - } - if (pool.pp > Pool.MAX_ENTRIES) - throw new PoolOverflow(); - putChar(poolbuf, poolCountIdx, pool.pp); - } - - /** Given a symbol, return its name-and-type. - */ - NameAndType nameType(Symbol sym) { - return new NameAndType(sym.name, sym.externalType(types), types); - // the NameAndType is generated from a symbol reference, and the - // adjustment of adding an additional this$n parameter needs to be made. - } - /****************************************************************** * Writing Attributes ******************************************************************/ @@ -520,7 +276,8 @@ * position past attribute length index. */ int writeAttr(Name attrName) { - databuf.appendChar(pool.put(attrName)); + int index = poolWriter.putName(attrName); + databuf.appendChar(index); databuf.appendInt(0); return databuf.length; } @@ -567,8 +324,8 @@ || c.owner.kind != MTH) // or member init ? null : (MethodSymbol)c.owner; - databuf.appendChar(pool.put(enclClass)); - databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner))); + databuf.appendChar(poolWriter.putClass(enclClass)); + databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner)); endAttr(alenIdx); return 1; } @@ -594,11 +351,11 @@ if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC && (flags & ANONCONSTR) == 0 && (!types.isSameType(sym.type, sym.erasure(types)) || - signatureGen.hasTypeVar(sym.type.getThrownTypes()))) { + poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) { // note that a local class with captured variables // will get a signature attribute int alenIdx = writeAttr(names.Signature); - databuf.appendChar(pool.put(typeSig(sym.type))); + databuf.appendChar(poolWriter.putSignature(sym)); endAttr(alenIdx); acount++; } @@ -621,7 +378,7 @@ final int flags = ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | ((int) m.flags() & SYNTHETIC); - databuf.appendChar(pool.put(s.name)); + databuf.appendChar(poolWriter.putName(s.name)); databuf.appendChar(flags); } // Now write the real parameters @@ -629,7 +386,7 @@ final int flags = ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | ((int) m.flags() & SYNTHETIC); - databuf.appendChar(pool.put(s.name)); + databuf.appendChar(poolWriter.putName(s.name)); databuf.appendChar(flags); } // Now write the captured locals @@ -637,7 +394,7 @@ final int flags = ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | ((int) m.flags() & SYNTHETIC); - databuf.appendChar(pool.put(s.name)); + databuf.appendChar(poolWriter.putName(s.name)); databuf.appendChar(flags); } endAttr(attrIndex); @@ -803,50 +560,51 @@ */ class AttributeWriter implements Attribute.Visitor { public void visitConstant(Attribute.Constant _value) { - Object value = _value.value; - switch (_value.type.getTag()) { - case BYTE: - databuf.appendByte('B'); - break; - case CHAR: - databuf.appendByte('C'); - break; - case SHORT: - databuf.appendByte('S'); - break; - case INT: - databuf.appendByte('I'); - break; - case LONG: - databuf.appendByte('J'); - break; - case FLOAT: - databuf.appendByte('F'); - break; - case DOUBLE: - databuf.appendByte('D'); - break; - case BOOLEAN: - databuf.appendByte('Z'); - break; - case CLASS: - Assert.check(value instanceof String); + if (_value.type.getTag() == CLASS) { + Assert.check(_value.value instanceof String); + String s = (String)_value.value; databuf.appendByte('s'); - value = names.fromString(value.toString()); // CONSTANT_Utf8 - break; - default: - throw new AssertionError(_value.type); + databuf.appendChar(poolWriter.putName(names.fromString(s))); + } else { + switch (_value.type.getTag()) { + case BYTE: + databuf.appendByte('B'); + break; + case CHAR: + databuf.appendByte('C'); + break; + case SHORT: + databuf.appendByte('S'); + break; + case INT: + databuf.appendByte('I'); + break; + case LONG: + databuf.appendByte('J'); + break; + case FLOAT: + databuf.appendByte('F'); + break; + case DOUBLE: + databuf.appendByte('D'); + break; + case BOOLEAN: + databuf.appendByte('Z'); + break; + default: + throw new AssertionError(_value.type); + } + databuf.appendChar(poolWriter.putConstant(_value.value)); } - databuf.appendChar(pool.put(value)); } public void visitEnum(Attribute.Enum e) { databuf.appendByte('e'); - databuf.appendChar(pool.put(typeSig(e.value.type))); - databuf.appendChar(pool.put(e.value.name)); + databuf.appendChar(poolWriter.putDescriptor(e.value.type)); + databuf.appendChar(poolWriter.putName(e.value.name)); } public void visitClass(Attribute.Class clazz) { databuf.appendByte('c'); - databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType)))); + databuf.appendChar(poolWriter.putDescriptor(clazz.classType)); } public void visitCompound(Attribute.Compound compound) { databuf.appendByte('@'); @@ -867,10 +625,10 @@ /** Write a compound attribute excluding the '@' marker. */ void writeCompoundAttribute(Attribute.Compound c) { - databuf.appendChar(pool.put(typeSig(c.type))); + databuf.appendChar(poolWriter.putDescriptor(c.type)); databuf.appendChar(c.values.length()); for (Pair p : c.values) { - databuf.appendChar(pool.put(p.fst.name)); + databuf.appendChar(poolWriter.putName(p.fst.name)); p.snd.accept(awriter); } } @@ -974,9 +732,9 @@ int alenIdx = writeAttr(names.Module); - databuf.appendChar(pool.put(m)); + databuf.appendChar(poolWriter.putModule(m)); databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags - databuf.appendChar(m.version != null ? pool.put(m.version) : 0); + databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0); ListBuffer requires = new ListBuffer<>(); for (RequiresDirective r: m.requires) { @@ -985,22 +743,22 @@ } databuf.appendChar(requires.size()); for (RequiresDirective r: requires) { - databuf.appendChar(pool.put(r.module)); + databuf.appendChar(poolWriter.putModule(r.module)); databuf.appendChar(RequiresFlag.value(r.flags)); - databuf.appendChar(r.module.version != null ? pool.put(r.module.version) : 0); + databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0); } List exports = m.exports; databuf.appendChar(exports.size()); for (ExportsDirective e: exports) { - databuf.appendChar(pool.put(e.packge)); + databuf.appendChar(poolWriter.putPackage(e.packge)); databuf.appendChar(ExportsFlag.value(e.flags)); if (e.modules == null) { databuf.appendChar(0); } else { databuf.appendChar(e.modules.size()); for (ModuleSymbol msym: e.modules) { - databuf.appendChar(pool.put(msym)); + databuf.appendChar(poolWriter.putModule(msym)); } } } @@ -1008,14 +766,14 @@ List opens = m.opens; databuf.appendChar(opens.size()); for (OpensDirective o: opens) { - databuf.appendChar(pool.put(o.packge)); + databuf.appendChar(poolWriter.putPackage(o.packge)); databuf.appendChar(OpensFlag.value(o.flags)); if (o.modules == null) { databuf.appendChar(0); } else { databuf.appendChar(o.modules.size()); for (ModuleSymbol msym: o.modules) { - databuf.appendChar(pool.put(msym)); + databuf.appendChar(poolWriter.putModule(msym)); } } } @@ -1023,7 +781,7 @@ List uses = m.uses; databuf.appendChar(uses.size()); for (UsesDirective s: uses) { - databuf.appendChar(pool.put(s.service)); + databuf.appendChar(poolWriter.putClass(s.service)); } // temporary fix to merge repeated provides clause for same service; @@ -1035,9 +793,9 @@ } databuf.appendChar(mergedProvides.size()); mergedProvides.forEach((srvc, impls) -> { - databuf.appendChar(pool.put(srvc)); + databuf.appendChar(poolWriter.putClass(srvc)); databuf.appendChar(impls.size()); - impls.forEach(impl -> databuf.appendChar(pool.put(impl))); + impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl))); }); endAttr(alenIdx); @@ -1048,46 +806,12 @@ * Writing Objects **********************************************************************/ - /** Enter an inner class into the `innerClasses' set/queue. - */ - void enterInner(ClassSymbol c) { - if (c.type.isCompound()) { - throw new AssertionError("Unexpected intersection type: " + c.type); - } - try { - c.complete(); - } catch (CompletionFailure ex) { - System.err.println("error: " + c + ": " + ex.getMessage()); - throw ex; - } - if (!c.type.hasTag(CLASS)) return; // arrays - if (pool != null && // pool might be null if called from xClassName - c.owner.enclClass() != null && - (innerClasses == null || !innerClasses.contains(c))) { -// log.errWriter.println("enter inner " + c);//DEBUG - enterInner(c.owner.enclClass()); - pool.put(c); - if (c.name != names.empty) - pool.put(c.name); - if (innerClasses == null) { - innerClasses = new HashSet<>(); - innerClassesQueue = new ListBuffer<>(); - pool.put(names.InnerClasses); - } - innerClasses.add(c); - innerClassesQueue.append(c); - } - } - /** Write "inner classes" attribute. */ void writeInnerClasses() { int alenIdx = writeAttr(names.InnerClasses); - databuf.appendChar(innerClassesQueue.length()); - for (List l = innerClassesQueue.toList(); - l.nonEmpty(); - l = l.tail) { - ClassSymbol inner = l.head; + databuf.appendChar(poolWriter.innerClasses.size()); + for (ClassSymbol inner : poolWriter.innerClasses) { inner.markAbstractIfNeeded(types); char flags = (char) adjustFlags(inner.flags_field); if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT @@ -1097,11 +821,11 @@ pw.println("INNERCLASS " + inner.name); pw.println("---" + flagNames(flags)); } - databuf.appendChar(pool.get(inner)); + databuf.appendChar(poolWriter.putClass(inner)); databuf.appendChar( - inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0); + inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0); databuf.appendChar( - !inner.name.isEmpty() ? pool.get(inner.name) : 0); + !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0); databuf.appendChar(flags); } endAttr(alenIdx); @@ -1111,14 +835,14 @@ * Write NestMembers attribute (if needed) */ int writeNestMembersIfNeeded(ClassSymbol csym) { - ListBuffer nested = new ListBuffer<>(); + ListBuffer nested = new ListBuffer<>(); listNested(csym, nested); - Set nestedUnique = new LinkedHashSet<>(nested); + Set nestedUnique = new LinkedHashSet<>(nested); if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) { int alenIdx = writeAttr(names.NestMembers); databuf.appendChar(nestedUnique.size()); - for (Symbol s : nestedUnique) { - databuf.appendChar(pool.put(s)); + for (ClassSymbol s : nestedUnique) { + databuf.appendChar(poolWriter.putClass(s)); } endAttr(alenIdx); return 1; @@ -1132,14 +856,14 @@ int writeNestHostIfNeeded(ClassSymbol csym) { if (csym.owner.kind != PCK) { int alenIdx = writeAttr(names.NestHost); - databuf.appendChar(pool.put(csym.outermostClass())); + databuf.appendChar(poolWriter.putClass(csym.outermostClass())); endAttr(alenIdx); return 1; } return 0; } - private void listNested(Symbol sym, ListBuffer seen) { + private void listNested(Symbol sym, ListBuffer seen) { if (sym.kind != TYP) return; ClassSymbol csym = (ClassSymbol)sym; if (csym.owner.kind != PCK) { @@ -1161,17 +885,16 @@ */ void writeBootstrapMethods() { int alenIdx = writeAttr(names.BootstrapMethods); - databuf.appendChar(bootstrapMethods.size()); - for (Map.Entry entry : bootstrapMethods.entrySet()) { - DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey(); + databuf.appendChar(poolWriter.bootstrapMethods.size()); + for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) { //write BSM handle - databuf.appendChar(pool.get(entry.getValue().mh)); - Object[] uniqueArgs = bsmKey.getUniqueArgs(); + databuf.appendChar(poolWriter.putConstant(bsmKey.bsm)); + LoadableConstant[] uniqueArgs = bsmKey.staticArgs; //write static args length databuf.appendChar(uniqueArgs.length); //write static args array - for (Object o : uniqueArgs) { - databuf.appendChar(pool.get(o)); + for (LoadableConstant arg : uniqueArgs) { + databuf.appendChar(poolWriter.putConstant(arg)); } } endAttr(alenIdx); @@ -1187,13 +910,13 @@ pw.println("FIELD " + v.name); pw.println("---" + flagNames(v.flags())); } - databuf.appendChar(pool.put(v.name)); - databuf.appendChar(pool.put(typeSig(v.erasure(types)))); + databuf.appendChar(poolWriter.putName(v.name)); + databuf.appendChar(poolWriter.putDescriptor(v)); int acountIdx = beginAttrs(); int acount = 0; if (v.getConstValue() != null) { int alenIdx = writeAttr(names.ConstantValue); - databuf.appendChar(pool.put(v.getConstValue())); + databuf.appendChar(poolWriter.putConstant(v.getConstValue())); endAttr(alenIdx); acount++; } @@ -1211,8 +934,8 @@ pw.println("METHOD " + m.name); pw.println("---" + flagNames(m.flags())); } - databuf.appendChar(pool.put(m.name)); - databuf.appendChar(pool.put(typeSig(m.externalType(types)))); + databuf.appendChar(poolWriter.putName(m.name)); + databuf.appendChar(poolWriter.putDescriptor(m)); int acountIdx = beginAttrs(); int acount = 0; if (m.code != null) { @@ -1227,7 +950,7 @@ int alenIdx = writeAttr(names.Exceptions); databuf.appendChar(thrown.length()); for (List l = thrown; l.nonEmpty(); l = l.tail) - databuf.appendChar(pool.put(l.head.tsym)); + databuf.appendChar(poolWriter.putClass(l.head)); endAttr(alenIdx); acount++; } @@ -1303,9 +1026,8 @@ && (r.start_pc + r.length) <= code.cp); databuf.appendChar(r.length); VarSymbol sym = var.sym; - databuf.appendChar(pool.put(sym.name)); - Type vartype = sym.erasure(types); - databuf.appendChar(pool.put(typeSig(vartype))); + databuf.appendChar(poolWriter.putName(sym.name)); + databuf.appendChar(poolWriter.putDescriptor(sym)); databuf.appendChar(var.reg); if (needsLocalVariableTypeEntry(var.sym.type)) { nGenericVars++; @@ -1329,8 +1051,8 @@ // write variable info databuf.appendChar(r.start_pc); databuf.appendChar(r.length); - databuf.appendChar(pool.put(sym.name)); - databuf.appendChar(pool.put(typeSig(sym.type))); + databuf.appendChar(poolWriter.putName(sym.name)); + databuf.appendChar(poolWriter.putSignature(sym)); databuf.appendChar(var.reg); count++; } @@ -1457,14 +1179,10 @@ break; case CLASS: case ARRAY: - if (debugstackmap) System.out.print("object(" + t + ")"); - databuf.appendByte(7); - databuf.appendChar(pool.put(t)); - break; case TYPEVAR: if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")"); databuf.appendByte(7); - databuf.appendChar(pool.put(types.erasure(t).tsym)); + databuf.appendChar(poolWriter.putClass(types.erasure(t))); break; case UNINITIALIZED_THIS: if (debugstackmap) System.out.print("uninit_this"); @@ -1763,11 +1481,6 @@ Assert.check((c.flags() & COMPOUND) == 0); databuf.reset(); poolbuf.reset(); - signatureGen.reset(); - pool = c.pool; - innerClasses = null; - innerClassesQueue = null; - bootstrapMethods = new LinkedHashMap<>(); Type supertype = types.supertype(c.type); List interfaces = types.interfaces(c.type); @@ -1793,14 +1506,14 @@ if (c.owner.kind == MDL) { PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage; - databuf.appendChar(pool.put(new ClassSymbol(0, names.module_info, unnamed))); + databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed))); } else { - databuf.appendChar(pool.put(c)); + databuf.appendChar(poolWriter.putClass(c)); } - databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0); + databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0); databuf.appendChar(interfaces.length()); for (List l = interfaces; l.nonEmpty(); l = l.tail) - databuf.appendChar(pool.put(l.head.tsym)); + databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym)); int fieldsCount = 0; int methodsCount = 0; for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) { @@ -1808,14 +1521,14 @@ case VAR: fieldsCount++; break; case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++; break; - case TYP: enterInner((ClassSymbol)sym); break; + case TYP: poolWriter.enterInner((ClassSymbol)sym); break; default : Assert.error(); } } if (c.trans_local != null) { for (ClassSymbol local : c.trans_local) { - enterInner(local); + poolWriter.enterInner(local); } } @@ -1833,12 +1546,7 @@ sigReq = l.head.allparams().length() != 0; if (sigReq) { int alenIdx = writeAttr(names.Signature); - if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams); - signatureGen.assembleSig(supertype); - for (List l = interfaces; l.nonEmpty(); l = l.tail) - signatureGen.assembleSig(l.head); - databuf.appendChar(pool.put(signatureGen.toName())); - signatureGen.reset(); + databuf.appendChar(poolWriter.putSignature(c)); endAttr(alenIdx); acount++; } @@ -1848,9 +1556,8 @@ // WHM 6/29/1999: Strip file path prefix. We do it here at // the last possible moment because the sourcefile may be used // elsewhere in error diagnostics. Fixes 4241573. - //databuf.appendChar(c.pool.put(c.sourcefile)); String simpleName = PathFileObject.getSimpleName(c.sourcefile); - databuf.appendChar(c.pool.put(names.fromString(simpleName))); + databuf.appendChar(poolWriter.putName(names.fromString(simpleName))); endAttr(alenIdx); acount++; } @@ -1858,12 +1565,12 @@ if (genCrt) { // Append SourceID attribute int alenIdx = writeAttr(names.SourceID); - databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile))))); + databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile))))); endAttr(alenIdx); acount++; // Append CompilationID attribute alenIdx = writeAttr(names.CompilationID); - databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis())))); + databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis())))); endAttr(alenIdx); acount++; } @@ -1893,24 +1600,24 @@ } } - writePool(c.pool); - - if (innerClasses != null) { - writeInnerClasses(); + if (!poolWriter.bootstrapMethods.isEmpty()) { + writeBootstrapMethods(); acount++; } - if (!bootstrapMethods.isEmpty()) { - writeBootstrapMethods(); + if (!poolWriter.innerClasses.isEmpty()) { + writeInnerClasses(); acount++; } endAttrs(acountIdx, acount); - poolbuf.appendBytes(databuf.elems, 0, databuf.length); out.write(poolbuf.elems, 0, poolbuf.length); - pool = c.pool = null; // to conserve space + poolWriter.writePool(out); + poolWriter.reset(); // to save space + + out.write(databuf.elems, 0, databuf.length); } /**Allows subclasses to write additional class attributes diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Fri Apr 19 08:00:42 2019 -0400 @@ -27,15 +27,27 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.resources.CompilerProperties.Errors; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import java.util.function.ToIntBiFunction; +import java.util.function.ToIntFunction; + import static com.sun.tools.javac.code.TypeTag.BOT; import static com.sun.tools.javac.code.TypeTag.INT; import static com.sun.tools.javac.jvm.ByteCodes.*; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String; import static com.sun.tools.javac.jvm.UninitializedType.*; import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame; @@ -72,6 +84,7 @@ final Types types; final Symtab syms; + final PoolWriter poolWriter; /*---------- classfile fields: --------------- */ @@ -177,10 +190,6 @@ */ Position.LineMap lineMap; - /** The constant pool of the current class. - */ - final Pool pool; - final MethodSymbol meth; private int letExprStackPos = 0; @@ -197,7 +206,7 @@ CRTable crt, Symtab syms, Types types, - Pool pool) { + PoolWriter poolWriter) { this.meth = meth; this.fatcode = fatcode; this.lineMap = lineMap; @@ -206,6 +215,7 @@ this.crt = crt; this.syms = syms; this.types = types; + this.poolWriter = poolWriter; this.debugCode = debugCode; this.stackMap = stackMap; switch (stackMap) { @@ -218,7 +228,6 @@ } state = new State(); lvar = new LocalVar[20]; - this.pool = pool; } @@ -389,12 +398,13 @@ /** Emit a ldc (or ldc_w) instruction, taking into account operand size */ - public void emitLdc(int od) { + public void emitLdc(LoadableConstant constant) { + int od = poolWriter.putConstant(constant); if (od <= 255) { - emitop1(ldc1, od); + emitop1(ldc1, od, constant); } else { - emitop2(ldc2, od); + emitop2(ldc2, od, constant); } } @@ -431,11 +441,11 @@ /** Emit an invokeinterface instruction. */ - public void emitInvokeinterface(int meth, Type mtype) { + public void emitInvokeinterface(Symbol member, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokeinterface); if (!alive) return; - emit2(meth); + emit2(poolWriter.putMember(member)); emit1(argsize + 1); emit1(0); state.pop(argsize + 1); @@ -444,14 +454,13 @@ /** Emit an invokespecial instruction. */ - public void emitInvokespecial(int meth, Type mtype) { + public void emitInvokespecial(Symbol member, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokespecial); if (!alive) return; - emit2(meth); - Symbol sym = (Symbol)pool.pool[meth]; + emit2(poolWriter.putMember(member)); state.pop(argsize); - if (sym.isConstructor()) + if (member.isConstructor()) state.markInitialized((UninitializedType)state.peek()); state.pop(1); state.push(mtype.getReturnType()); @@ -459,33 +468,33 @@ /** Emit an invokestatic instruction. */ - public void emitInvokestatic(int meth, Type mtype) { + public void emitInvokestatic(Symbol member, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokestatic); if (!alive) return; - emit2(meth); + emit2(poolWriter.putMember(member)); state.pop(argsize); state.push(mtype.getReturnType()); } /** Emit an invokevirtual instruction. */ - public void emitInvokevirtual(int meth, Type mtype) { + public void emitInvokevirtual(Symbol member, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokevirtual); if (!alive) return; - emit2(meth); + emit2(poolWriter.putMember(member)); state.pop(argsize + 1); state.push(mtype.getReturnType()); } /** Emit an invokedynamic instruction. */ - public void emitInvokedynamic(int desc, Type mtype) { + public void emitInvokedynamic(DynamicMethodSymbol dynMember, Type mtype) { int argsize = width(mtype.getParameterTypes()); emitop(invokedynamic); if (!alive) return; - emit2(desc); + emit2(poolWriter.putDynamic(dynMember)); emit2(0); state.pop(argsize); state.push(mtype.getReturnType()); @@ -896,6 +905,10 @@ /** Emit an opcode with a one-byte operand field. */ public void emitop1(int op, int od) { + emitop1(op, od, null); + } + + public void emitop1(int op, int od, PoolConstant data) { emitop(op); if (!alive) return; emit1(od); @@ -904,7 +917,7 @@ state.push(syms.intType); break; case ldc1: - state.push(typeForPool(pool.pool[od])); + state.push(types.constantType((LoadableConstant)data)); break; default: throw new AssertionError(mnem(op)); @@ -912,25 +925,6 @@ postop(); } - /** The type of a constant pool entry. */ - private Type typeForPool(Object o) { - if (o instanceof Integer) return syms.intType; - if (o instanceof Float) return syms.floatType; - if (o instanceof String) return syms.stringType; - if (o instanceof Long) return syms.longType; - if (o instanceof Double) return syms.doubleType; - if (o instanceof ClassSymbol) return syms.classType; - if (o instanceof Pool.MethodHandle) return syms.methodHandleType; - if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type); - if (o instanceof Type) { - Type ty = (Type) o; - - if (ty instanceof Type.ArrayType) return syms.classType; - if (ty instanceof Type.MethodType) return syms.methodTypeType; - } - throw new AssertionError("Invalid type of constant pool entry: " + o.getClass()); - } - /** Emit an opcode with a one-byte operand field; * widen if field does not fit in a byte. */ @@ -1003,29 +997,31 @@ /** Emit an opcode with a two-byte operand field. */ + public

    void emitop2(int op, P constant, ToIntBiFunction poolFunc) { + int od = poolFunc.applyAsInt(poolWriter, constant); + emitop2(op, od, constant); + } + public void emitop2(int op, int od) { + emitop2(op, od, null); + } + + public void emitop2(int op, int od, PoolConstant data) { emitop(op); if (!alive) return; emit2(od); switch (op) { case getstatic: - state.push(((Symbol)(pool.pool[od])).erasure(types)); + state.push(((Symbol)data).erasure(types)); break; case putstatic: - state.pop(((Symbol)(pool.pool[od])).erasure(types)); + state.pop(((Symbol)data).erasure(types)); break; - case new_: - Symbol sym; - if (pool.pool[od] instanceof UniqueType) { - // Required by change in Gen.makeRef to allow - // annotated types. - // TODO: is this needed anywhere else? - sym = ((UniqueType)(pool.pool[od])).type.tsym; - } else { - sym = (Symbol)(pool.pool[od]); - } - state.push(uninitializedObject(sym.erasure(types), cp-3)); + case new_: { + Type t = (Type)data; + state.push(uninitializedObject(t.tsym.erasure(types), cp-3)); break; + } case sipush: state.push(syms.intType); break; @@ -1053,30 +1049,27 @@ markDead(); break; case putfield: - state.pop(((Symbol)(pool.pool[od])).erasure(types)); + state.pop(((Symbol)data).erasure(types)); state.pop(1); // object ref break; case getfield: state.pop(1); // object ref - state.push(((Symbol)(pool.pool[od])).erasure(types)); + state.push(((Symbol)data).erasure(types)); break; case checkcast: { state.pop(1); // object ref - Object o = pool.pool[od]; - Type t = (o instanceof Symbol) - ? ((Symbol)o).erasure(types) - : types.erasure((((UniqueType)o).type)); + Type t = types.erasure((Type)data); state.push(t); break; } case ldc2w: - state.push(typeForPool(pool.pool[od])); + state.push(types.constantType((LoadableConstant)data)); break; case instanceof_: state.pop(1); state.push(syms.intType); break; case ldc2: - state.push(typeForPool(pool.pool[od])); + state.push(types.constantType((LoadableConstant)data)); break; case jsr: break; diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Apr 19 08:00:42 2019 -0400 @@ -25,6 +25,7 @@ package com.sun.tools.javac.jvm; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.tree.TreeInfo.PosKind; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -88,9 +89,9 @@ return instance; } - /** Constant pool, reset by genClass. + /** Constant pool writer, set by genClass. */ - private final Pool pool; + final PoolWriter poolWriter; protected Gen(Context context) { context.put(genKey, this); @@ -121,7 +122,7 @@ genCrt = options.isSet(XJCOV); debugCode = options.isSet("debug.code"); disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke"); - pool = new Pool(types); + poolWriter = new PoolWriter(types, names); // ignore cldc because we cannot have both stackmap formats this.stackMap = StackMapFormat.JSR202; @@ -252,17 +253,17 @@ * @param type The type for which a reference is inserted. */ int makeRef(DiagnosticPosition pos, Type type) { - checkDimension(pos, type); - if (type.isAnnotated()) { - return pool.put((Object)type); - } else { - return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type); - } + return poolWriter.putClass(checkDimension(pos, type)); } /** Check if the given type is an array with too many dimensions. */ - private void checkDimension(DiagnosticPosition pos, Type t) { + private Type checkDimension(DiagnosticPosition pos, Type t) { + checkDimensionInternal(pos, t); + return t; + } + + private void checkDimensionInternal(DiagnosticPosition pos, Type t) { switch (t.getTag()) { case METHOD: checkDimension(pos, t.getReturnType()); @@ -516,7 +517,7 @@ if (nerrs != 0 || // only complain about a long string once constValue == null || !(constValue instanceof String) || - ((String)constValue).length() < Pool.MAX_STRING_LENGTH) + ((String)constValue).length() < PoolWriter.MAX_STRING_LENGTH) return; log.error(pos, Errors.LimitString); nerrs++; @@ -806,7 +807,7 @@ @Override public void visitIdent(JCIdent tree) { if (tree.sym.owner instanceof ClassSymbol) { - pool.put(tree.sym.owner); + poolWriter.putClass((ClassSymbol)tree.sym.owner); } } @@ -1007,8 +1008,8 @@ : null, syms, types, - pool); - items = new Items(pool, code, syms, types); + poolWriter); + items = new Items(poolWriter, code, syms, types); if (code.debugCode) { System.err.println(meth + " for body " + tree); } @@ -1886,7 +1887,7 @@ Assert.check(tree.encl == null && tree.def == null); setTypeAnnotationPositions(tree.pos); - code.emitop2(new_, makeRef(tree.pos(), tree.type)); + code.emitop2(new_, checkDimension(tree.pos(), tree.type), PoolWriter::putClass); code.emitop0(dup); // Generate code for all arguments, where the expected types are @@ -2162,7 +2163,7 @@ if (!tree.clazz.type.isPrimitive() && !types.isSameType(tree.expr.type, tree.clazz.type) && types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) { - code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type)); + code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass); } } @@ -2221,7 +2222,7 @@ Symbol sym = tree.sym; if (tree.name == names._class) { - code.emitLdc(makeRef(tree.pos(), tree.selected.type)); + code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type)); result = items.makeStackItem(pt); return; } @@ -2305,7 +2306,7 @@ code.endScopes(limit); } - private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) { + private void generateReferencesToPrunedTree(ClassSymbol classSymbol) { List prunedInfo = lower.prunedTree.get(classSymbol); if (prunedInfo != null) { for (JCTree prunedTree: prunedInfo) { @@ -2331,12 +2332,10 @@ ClassSymbol c = cdef.sym; this.toplevel = env.toplevel; this.endPosTable = toplevel.endPositions; - c.pool = pool; - pool.reset(); /* method normalizeDefs() can add references to external classes into the constant pool */ cdef.defs = normalizeDefs(cdef.defs, c); - generateReferencesToPrunedTree(c, pool); + generateReferencesToPrunedTree(c); Env localEnv = new Env<>(cdef, new GenContext()); localEnv.toplevel = env.toplevel; localEnv.enclClass = cdef; @@ -2344,7 +2343,7 @@ for (List l = cdef.defs; l.nonEmpty(); l = l.tail) { genDef(l.head, localEnv); } - if (pool.numEntries() > Pool.MAX_ENTRIES) { + if (poolWriter.size() > PoolWriter.MAX_ENTRIES) { log.error(cdef.pos(), Errors.LimitPool); nerrs++; } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java Fri Apr 19 08:00:42 2019 -0400 @@ -29,6 +29,8 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.jvm.Code.*; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Assert; @@ -50,9 +52,9 @@ */ public class Items { - /** The current constant pool. + /** The current constant pool writer. */ - Pool pool; + PoolWriter poolWriter; /** The current code buffer. */ @@ -72,9 +74,9 @@ private final Item superItem; private final Item[] stackItem = new Item[TypeCodeCount]; - public Items(Pool pool, Code code, Symtab syms, Types types) { + public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) { this.code = code; - this.pool = pool; + this.poolWriter = poolWriter; this.types = types; voidItem = new Item(VOIDcode) { public String toString() { return "void"; } @@ -444,18 +446,18 @@ } Item load() { - code.emitop2(getstatic, pool.put(member)); + code.emitop2(getstatic, member, PoolWriter::putMember); return stackItem[typecode]; } void store() { - code.emitop2(putstatic, pool.put(member)); + code.emitop2(putstatic, member, PoolWriter::putMember); } Item invoke() { MethodType mtype = (MethodType)member.erasure(types); int rescode = Code.typecode(mtype.restype); - code.emitInvokestatic(pool.put(member), mtype); + code.emitInvokestatic(member, mtype); return stackItem[rescode]; } @@ -484,7 +486,7 @@ // assert target.hasNativeInvokeDynamic(); MethodType mtype = (MethodType)member.erasure(types); int rescode = Code.typecode(mtype.restype); - code.emitInvokedynamic(pool.put(member), mtype); + code.emitInvokedynamic((DynamicMethodSymbol)member, mtype); return stackItem[rescode]; } @@ -512,23 +514,23 @@ } Item load() { - code.emitop2(getfield, pool.put(member)); + code.emitop2(getfield, member, PoolWriter::putMember); return stackItem[typecode]; } void store() { - code.emitop2(putfield, pool.put(member)); + code.emitop2(putfield, member, PoolWriter::putMember); } Item invoke() { MethodType mtype = (MethodType)member.externalType(types); int rescode = Code.typecode(mtype.restype); if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) { - code.emitInvokeinterface(pool.put(member), mtype); + code.emitInvokeinterface(member, mtype); } else if (nonvirtual) { - code.emitInvokespecial(pool.put(member), mtype); + code.emitInvokespecial(member, mtype); } else { - code.emitInvokevirtual(pool.put(member), mtype); + code.emitInvokevirtual(member, mtype); } return stackItem[rescode]; } @@ -560,26 +562,50 @@ /** The literal's value. */ - Object value; + final LoadableConstant value; ImmediateItem(Type type, Object value) { super(Code.typecode(type)); - this.value = value; + switch (typecode) { + case BYTEcode: + case SHORTcode: + case CHARcode: + case INTcode: + this.value = LoadableConstant.Int((int)value); + break; + case LONGcode: + this.value = LoadableConstant.Long((long)value); + break; + case FLOATcode: + this.value = LoadableConstant.Float((float)value); + break; + case DOUBLEcode: + this.value = LoadableConstant.Double((double)value); + break; + case OBJECTcode: + this.value = LoadableConstant.String((String)value); + break; + default: + throw new UnsupportedOperationException("unsupported tag: " + typecode); + } } private void ldc() { - int idx = pool.put(value); if (typecode == LONGcode || typecode == DOUBLEcode) { - code.emitop2(ldc2w, idx); + code.emitop2(ldc2w, value, PoolWriter::putConstant); } else { - code.emitLdc(idx); + code.emitLdc(value); } } + private Number numericValue() { + return (Number)((BasicConstant)value).data; + } + Item load() { switch (typecode) { case INTcode: case BYTEcode: case SHORTcode: case CHARcode: - int ival = ((Number)value).intValue(); + int ival = numericValue().intValue(); if (-1 <= ival && ival <= 5) code.emitop0(iconst_0 + ival); else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE) @@ -590,14 +616,14 @@ ldc(); break; case LONGcode: - long lval = ((Number)value).longValue(); + long lval = numericValue().longValue(); if (lval == 0 || lval == 1) code.emitop0(lconst_0 + (int)lval); else ldc(); break; case FLOATcode: - float fval = ((Number)value).floatValue(); + float fval = numericValue().floatValue(); if (isPosZero(fval) || fval == 1.0 || fval == 2.0) code.emitop0(fconst_0 + (int)fval); else { @@ -605,7 +631,7 @@ } break; case DOUBLEcode: - double dval = ((Number)value).doubleValue(); + double dval = numericValue().doubleValue(); if (isPosZero(dval) || dval == 1.0) code.emitop0(dconst_0 + (int)dval); else @@ -632,7 +658,7 @@ } CondItem mkCond() { - int ival = ((Number)value).intValue(); + int ival = numericValue().intValue(); return makeCondItem(ival != 0 ? goto_ : dontgoto); } @@ -647,31 +673,31 @@ else return new ImmediateItem( syms.intType, - ((Number)value).intValue()); + numericValue().intValue()); case LONGcode: return new ImmediateItem( syms.longType, - ((Number)value).longValue()); + numericValue().longValue()); case FLOATcode: return new ImmediateItem( syms.floatType, - ((Number)value).floatValue()); + numericValue().floatValue()); case DOUBLEcode: return new ImmediateItem( syms.doubleType, - ((Number)value).doubleValue()); + numericValue().doubleValue()); case BYTEcode: return new ImmediateItem( syms.byteType, - (int)(byte)((Number)value).intValue()); + (int)(byte)numericValue().intValue()); case CHARcode: return new ImmediateItem( syms.charType, - (int)(char)((Number)value).intValue()); + (int)(char)numericValue().intValue()); case SHORTcode: return new ImmediateItem( syms.shortType, - (int)(short)((Number)value).intValue()); + (int)(short)numericValue().intValue()); default: return super.coerce(targetcode); } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Fri Apr 19 08:00:42 2019 -0400 @@ -24,6 +24,9 @@ */ package com.sun.tools.javac.jvm; +import com.sun.tools.javac.util.ByteBuffer; +import com.sun.tools.javac.util.Name.NameMapper; + import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -55,16 +58,15 @@ /** The buffer containing the currently read class file. */ - private byte[] buf = new byte[INITIAL_BUFFER_SIZE]; + private ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE); /** The current input pointer. */ private int bp; - /** For every constant pool entry, an index into buf where the - * defining section of the entry is found. + /** The constant pool reader. */ - private int[] poolIdx; + private PoolReader reader; public ModuleNameReader() { } @@ -83,7 +85,8 @@ public String readModuleName(InputStream in) throws IOException, BadClassFile { bp = 0; - buf = readInputStream(buf, in); + buf.reset(); + buf.appendStream(in); int magic = nextInt(); if (magic != JAVA_MAGIC) @@ -94,7 +97,8 @@ if (majorVersion < 53) throw new BadClassFile("bad major version number for module: " + majorVersion); - indexPool(); + reader = new PoolReader(buf); + bp = reader.readPool(buf, bp); int access_flags = nextChar(); if (access_flags != 0x8000) @@ -110,8 +114,8 @@ for (int i = 0; i < attributes_count; i++) { int attr_name = nextChar(); int attr_length = nextInt(); - if (getUtf8Value(attr_name, false).equals("Module") && attr_length > 2) { - return getModuleName(nextChar()); + if (reader.peekName(attr_name, utf8Mapper(false)).equals("Module") && attr_length > 2) { + return reader.peekModuleName(nextChar(), utf8Mapper(true)); } else { // skip over unknown attributes bp += attr_length; @@ -125,132 +129,26 @@ throw new BadClassFile("invalid " + name + " for module: " + count); } - /** Extract a character at position bp from buf. - */ - char getChar(int bp) { - return - (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF)); - } - /** Read a character. */ char nextChar() { - return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); + char res = buf.getChar(bp); + bp += 2; + return res; } /** Read an integer. */ int nextInt() { - return - ((buf[bp++] & 0xFF) << 24) + - ((buf[bp++] & 0xFF) << 16) + - ((buf[bp++] & 0xFF) << 8) + - (buf[bp++] & 0xFF); - } - - /** Index all constant pool entries, writing their start addresses into - * poolIdx. - */ - void indexPool() throws BadClassFile { - poolIdx = new int[nextChar()]; - int i = 1; - while (i < poolIdx.length) { - poolIdx[i++] = bp; - byte tag = buf[bp++]; - switch (tag) { - case CONSTANT_Utf8: case CONSTANT_Unicode: { - int len = nextChar(); - bp = bp + len; - break; - } - case CONSTANT_Class: - case CONSTANT_String: - case CONSTANT_MethodType: - case CONSTANT_Module: - case CONSTANT_Package: - bp = bp + 2; - break; - case CONSTANT_MethodHandle: - bp = bp + 3; - break; - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - case CONSTANT_NameandType: - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_InvokeDynamic: - bp = bp + 4; - break; - case CONSTANT_Long: - case CONSTANT_Double: - bp = bp + 8; - i++; - break; - default: - throw new BadClassFile("malformed constant pool"); - } - } + int res = buf.getInt(bp); + bp += 4; + return res; } - String getUtf8Value(int index, boolean internalize) throws BadClassFile { - int utf8Index = poolIdx[index]; - if (buf[utf8Index] == CONSTANT_Utf8) { - int len = getChar(utf8Index + 1); - int start = utf8Index + 3; - if (internalize) { - return new String(ClassFile.internalize(buf, start, len)); - } else { - return new String(buf, start, len); - } - } - throw new BadClassFile("bad name at index " + index); - } - - String getModuleName(int index) throws BadClassFile { - int infoIndex = poolIdx[index]; - if (buf[infoIndex] == CONSTANT_Module) { - return getUtf8Value(getChar(infoIndex + 1), true); - } else { - throw new BadClassFile("bad module name at index " + index); - } + NameMapper utf8Mapper(boolean internalize) { + return internalize ? + (buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) : + String::new; } - private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { - try { - buf = ensureCapacity(buf, s.available()); - int r = s.read(buf); - int bp = 0; - while (r != -1) { - bp += r; - buf = ensureCapacity(buf, bp); - r = s.read(buf, bp, buf.length - bp); - } - return buf; - } finally { - try { - s.close(); - } catch (IOException e) { - /* Ignore any errors, as this stream may have already - * thrown a related exception which is the one that - * should be reported. - */ - } - } - } - - /* - * ensureCapacity will increase the buffer as needed, taking note that - * the new buffer will always be greater than the needed and never - * exactly equal to the needed size or bp. If equal then the read (above) - * will infinitely loop as buf.length - bp == 0. - */ - private static byte[] ensureCapacity(byte[] buf, int needed) { - if (buf.length <= needed) { - byte[] old = buf; - buf = new byte[Integer.highestOneBit(needed) << 1]; - System.arraycopy(old, 0, buf, 0, old.length); - } - return buf; - } } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.javac.jvm; - -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.code.TypeTag; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.code.Types.UniqueType; - -import com.sun.tools.javac.util.ArrayUtils; -import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.Filter; -import com.sun.tools.javac.util.Name; - -import java.util.*; - -import com.sun.tools.javac.util.DefinedBy; -import com.sun.tools.javac.util.DefinedBy.Api; - -import static com.sun.tools.javac.code.Kinds.*; -import static com.sun.tools.javac.code.Kinds.Kind.*; - -/** An internal structure that corresponds to the constant pool of a classfile. - * - *

    This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Pool { - - public static final int MAX_ENTRIES = 0xFFFF; - public static final int MAX_STRING_LENGTH = 0xFFFF; - - /** Index of next constant to be entered. - */ - int pp; - - /** The initial pool buffer. - */ - Object[] pool; - - /** A hashtable containing all constants in the pool. - */ - Map indices; - - Types types; - - /** Construct a pool with given number of elements and element array. - */ - public Pool(int pp, Object[] pool, Types types) { - this.pp = pp; - this.pool = pool; - this.types = types; - this.indices = new HashMap<>(pool.length); - for (int i = 1; i < pp; i++) { - if (pool[i] != null) indices.put(pool[i], i); - } - } - - /** Construct an empty pool. - */ - public Pool(Types types) { - this(1, new Object[64], types); - } - - /** Return the number of entries in the constant pool. - */ - public int numEntries() { - return pp; - } - - /** Remove everything from this pool. - */ - public void reset() { - pp = 1; - indices.clear(); - } - - /** Place an object in the pool, unless it is already there. - * If object is a symbol also enter its owner unless the owner is a - * package. Return the object's index in the pool. - */ - public int put(Object value) { - value = makePoolValue(value); - Assert.check(!(value instanceof Type.TypeVar)); - Assert.check(!(value instanceof Types.UniqueType && - ((UniqueType) value).type instanceof Type.TypeVar)); - Integer index = indices.get(value); - if (index == null) { - index = pp; - indices.put(value, index); - pool = ArrayUtils.ensureCapacity(pool, pp); - pool[pp++] = value; - if (value instanceof Long || value instanceof Double) { - pool = ArrayUtils.ensureCapacity(pool, pp); - pool[pp++] = null; - } - } - return index.intValue(); - } - - Object makePoolValue(Object o) { - if (o instanceof DynamicMethodSymbol) { - return new DynamicMethod((DynamicMethodSymbol)o, types); - } else if (o instanceof MethodSymbol) { - return new Method((MethodSymbol)o, types); - } else if (o instanceof VarSymbol) { - return new Variable((VarSymbol)o, types); - } else if (o instanceof Type) { - Type t = (Type)o; - // ClassRefs can come from ClassSymbols or from Types. - // Return the symbol for these types to avoid duplicates - // in the constant pool - if (t.hasTag(TypeTag.CLASS)) - return t.tsym; - else - return new UniqueType(t, types); - } else { - return o; - } - } - - /** Return the given object's index in the pool, - * or -1 if object is not in there. - */ - public int get(Object o) { - Integer n = indices.get(o); - return n == null ? -1 : n.intValue(); - } - - static class Method extends DelegatedSymbol { - UniqueType uniqueType; - Method(MethodSymbol m, Types types) { - super(m); - this.uniqueType = new UniqueType(m.type, types); - } - @DefinedBy(Api.LANGUAGE_MODEL) - public boolean equals(Object any) { - if (!(any instanceof Method)) return false; - MethodSymbol o = ((Method)any).other; - MethodSymbol m = this.other; - return - o.name == m.name && - o.owner == m.owner && - ((Method)any).uniqueType.equals(uniqueType); - } - @DefinedBy(Api.LANGUAGE_MODEL) - public int hashCode() { - MethodSymbol m = this.other; - return - m.name.hashCode() * 33 + - m.owner.hashCode() * 9 + - uniqueType.hashCode(); - } - } - - public static class DynamicMethod extends Method { - public Object[] uniqueStaticArgs; - - public DynamicMethod(DynamicMethodSymbol m, Types types) { - super(m, types); - uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public boolean equals(Object any) { - return equalsImpl(any, true); - } - - protected boolean equalsImpl(Object any, boolean includeDynamicArgs) { - if (includeDynamicArgs && !super.equals(any)) return false; - if (!(any instanceof DynamicMethod)) return false; - DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other; - DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other; - return dm1.bsm == dm2.bsm && - dm1.bsmKind == dm2.bsmKind && - Arrays.equals(uniqueStaticArgs, - ((DynamicMethod)any).uniqueStaticArgs); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public int hashCode() { - return hashCodeImpl(true); - } - - protected int hashCodeImpl(boolean includeDynamicArgs) { - int hash = includeDynamicArgs ? super.hashCode() : 0; - DynamicMethodSymbol dm = (DynamicMethodSymbol)other; - hash += dm.bsmKind * 7 + - dm.bsm.hashCode() * 11; - for (int i = 0; i < dm.staticArgs.length; i++) { - hash += (uniqueStaticArgs[i].hashCode() * 23); - } - return hash; - } - - private Object[] getUniqueTypeArray(Object[] objects, Types types) { - Object[] result = new Object[objects.length]; - for (int i = 0; i < objects.length; i++) { - if (objects[i] instanceof Type) { - result[i] = new UniqueType((Type)objects[i], types); - } else { - result[i] = objects[i]; - } - } - return result; - } - - static class BootstrapMethodsKey extends DynamicMethod { - BootstrapMethodsKey(DynamicMethodSymbol m, Types types) { - super(m, types); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public boolean equals(Object any) { - return equalsImpl(any, false); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public int hashCode() { - return hashCodeImpl(false); - } - - Object[] getUniqueArgs() { - return uniqueStaticArgs; - } - } - - static class BootstrapMethodsValue { - final MethodHandle mh; - final int index; - - public BootstrapMethodsValue(MethodHandle mh, int index) { - this.mh = mh; - this.index = index; - } - } - } - - static class Variable extends DelegatedSymbol { - UniqueType uniqueType; - Variable(VarSymbol v, Types types) { - super(v); - this.uniqueType = new UniqueType(v.type, types); - } - @DefinedBy(Api.LANGUAGE_MODEL) - public boolean equals(Object any) { - if (!(any instanceof Variable)) return false; - VarSymbol o = ((Variable)any).other; - VarSymbol v = other; - return - o.name == v.name && - o.owner == v.owner && - ((Variable)any).uniqueType.equals(uniqueType); - } - @DefinedBy(Api.LANGUAGE_MODEL) - public int hashCode() { - VarSymbol v = other; - return - v.name.hashCode() * 33 + - v.owner.hashCode() * 9 + - uniqueType.hashCode(); - } - } - - public static class MethodHandle { - - /** Reference kind - see ClassFile */ - int refKind; - - /** Reference symbol */ - Symbol refSym; - - UniqueType uniqueType; - - public MethodHandle(int refKind, Symbol refSym, Types types) { - this.refKind = refKind; - this.refSym = refSym; - this.uniqueType = new UniqueType(this.refSym.type, types); - checkConsistent(); - } - public boolean equals(Object other) { - if (!(other instanceof MethodHandle)) return false; - MethodHandle mr = (MethodHandle) other; - if (mr.refKind != refKind) return false; - Symbol o = mr.refSym; - return - o.name == refSym.name && - o.owner == refSym.owner && - ((MethodHandle)other).uniqueType.equals(uniqueType); - } - public int hashCode() { - return - refKind * 65 + - refSym.name.hashCode() * 33 + - refSym.owner.hashCode() * 9 + - uniqueType.hashCode(); - } - - /** - * Check consistency of reference kind and symbol (see JVMS 4.4.8) - */ - @SuppressWarnings("fallthrough") - private void checkConsistent() { - boolean staticOk = false; - Kind expectedKind = null; - Filter nameFilter = nonInitFilter; - boolean interfaceOwner = false; - switch (refKind) { - case ClassFile.REF_getStatic: - case ClassFile.REF_putStatic: - staticOk = true; - case ClassFile.REF_getField: - case ClassFile.REF_putField: - expectedKind = VAR; - break; - case ClassFile.REF_newInvokeSpecial: - nameFilter = initFilter; - expectedKind = MTH; - break; - case ClassFile.REF_invokeInterface: - interfaceOwner = true; - expectedKind = MTH; - break; - case ClassFile.REF_invokeStatic: - interfaceOwner = true; - staticOk = true; - case ClassFile.REF_invokeVirtual: - expectedKind = MTH; - break; - case ClassFile.REF_invokeSpecial: - interfaceOwner = true; - expectedKind = MTH; - break; - } - Assert.check(!refSym.isStatic() || staticOk); - Assert.check(refSym.kind == expectedKind); - Assert.check(nameFilter.accepts(refSym.name)); - Assert.check(!refSym.owner.isInterface() || interfaceOwner); - } - //where - Filter nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit); - - Filter initFilter = n -> n == n.table.names.init; - } -} diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.code.Types.UniqueType; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Pair; + +import java.util.Objects; +import java.util.stream.Stream; + +/** + * This interface models all javac entities that can be used to represent constant pool entries. + * A pool constant entity must (i) be associated with a constant pool entry tag and have a function + * which generates a key for the desired pool entry (so as to avoid duplicate entries when writing the + * constant pool). + */ +public interface PoolConstant { + + /** + * The constant pool entry key. + */ + default Object poolKey(Types types) { return this; } + + /** + * The constant pool entry tag. + */ + int poolTag(); + + /** + * The root of pool constants that can be loaded (e.g. with {@code ldc}, or appear as static + * arguments to a bootstrap method. + */ + interface LoadableConstant extends PoolConstant { + + /** + * Create a pool constant describing a given {@code int} value. + */ + static LoadableConstant Int(int i) { + return new BasicConstant(ClassFile.CONSTANT_Integer, i); + } + + /** + * Create a pool constant describing a given {@code float} value. + */ + static LoadableConstant Float(float f) { + return new BasicConstant(ClassFile.CONSTANT_Float, f); + } + + /** + * Create a pool constant describing a given {@code long} value. + */ + static LoadableConstant Long(long l) { + return new BasicConstant(ClassFile.CONSTANT_Long, l); + } + + /** + * Create a pool constant describing a given {@code double} value. + */ + static LoadableConstant Double(double d) { + return new BasicConstant(ClassFile.CONSTANT_Double, d); + } + + /** + * Create a pool constant describing a given {@code String} value. + */ + static LoadableConstant String(String s) { + return new BasicConstant(ClassFile.CONSTANT_String, s); + } + + /** + * This class models a pool constant of given basic type, one of {@code int}, {@code float}, + * {@code long}, {@code double} or {@code String}. + */ + class BasicConstant implements LoadableConstant { + int tag; + Object data; + + private BasicConstant(int tag, Object data) { + this.tag = tag; + this.data = data; + } + + @Override + public int poolTag() { + return tag; + } + + @Override + public Object poolKey(Types types) { + return data; + } + } + } + + /** + * This interface models a dynamic pool constant (either of kind {@code InvokeDynamic} or + * {@code ConstantDynamic}). In addition to the functionalities provided by the base interface, + * a dynamic pool constant must expose its dynamic type, bootstrap method and static argument list. + * Finally, a dynamic constant must have a way to compute a bootstrap method key - that is, + * a unique key for the bootstrap method entry it refers to, to avoid duplicates when writing + * the {@code BootstrapMethods} attribute. + */ + interface Dynamic extends PoolConstant { + + /** + * The dynamic constant's dynamic type. + */ + PoolConstant dynamicType(); + + /** + * The dynamic constant's static argument list. + */ + LoadableConstant[] staticArgs(); + + /** + * The dynamic constant's bootstrap method. + */ + LoadableConstant bootstrapMethod(); + + default BsmKey bsmKey(Types types) { + return new BsmKey(types, bootstrapMethod(), staticArgs()); + } + + @Override + default Object poolKey(Types types) { + return new Pair<>(bsmKey(types), dynamicType().poolKey(types)); + } + + /** + * A class modelling a bootstrap method key. + */ + class BsmKey { + /** + * The key's bootstrap method constant. + */ + public final LoadableConstant bsm; + + /** + * The key's static argument list. + */ + public final LoadableConstant[] staticArgs; + + private final Object bsmKey; + private final List staticArgKeys; + + private BsmKey(Types types, LoadableConstant bsm, LoadableConstant[] staticArgs) { + this.bsm = bsm; + this.bsmKey = bsm.poolKey(types); + this.staticArgs = staticArgs; + this.staticArgKeys = Stream.of(staticArgs) + .map(p -> p.poolKey(types)) + .collect(List.collector()); + } + + @Override + public int hashCode() { + return bsmKey.hashCode() + + staticArgKeys.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BsmKey) { + BsmKey other = (BsmKey)obj; + return Objects.equals(bsmKey, other.bsmKey) && + Objects.equals(staticArgKeys, other.staticArgKeys); + } else { + return false; + } + } + } + } + + /** + * A pool constant implememntation describing a name and type pool entry. + */ + final class NameAndType implements PoolConstant { + + final Name name; + final Type type; + + NameAndType(Name name, Type type) { + this.name = name; + this.type = type; + } + + @Override + public int poolTag() { + return ClassFile.CONSTANT_NameandType; + } + + @Override + public Object poolKey(Types types) { + return new Pair<>(name, new UniqueType(type, types)); + } + } +} diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.ModuleSymbol; +import com.sun.tools.javac.code.Symbol.PackageSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.jvm.PoolConstant.NameAndType; +import com.sun.tools.javac.util.ByteBuffer; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Name.NameMapper; +import com.sun.tools.javac.util.Names; + +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Dynamic; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InvokeDynamic; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Module; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_NameandType; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Package; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Utf8; +import static com.sun.tools.javac.jvm.ClassFile.internalize; + +/** + * Pool interface towards {@code ClassReader}. Exposes methods to decode and read javac entities + * from the constant pool. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class PoolReader { + + private final ClassReader reader; + private final ByteBuffer buf; + private final Names names; + private final Symtab syms; + + private ImmutablePoolHelper pool; + + PoolReader(ByteBuffer buf) { + this(null, buf, null, null); + } + + PoolReader(ClassReader reader, Names names, Symtab syms) { + this(reader, reader.buf, names, syms); + } + + PoolReader(ClassReader reader, ByteBuffer buf, Names names, Symtab syms) { + this.reader = reader; + this.buf = buf; + this.names = names; + this.syms = syms; + } + + /** + * Get a class symbol from the pool at given index. + */ + ClassSymbol getClass(int index) { + return pool.readIfNeeded(index); + } + + /** + * Get class name without resolving + */ + Z peekClassName(int index, NameMapper mapper) { + return peekName(buf.getChar(pool.offset(index)), mapper); + } + + /** + * Get package name without resolving + */ + Z peekPackageName(int index, NameMapper mapper) { + return peekName(buf.getChar(pool.offset(index)), mapper); + } + + /** + * Get module name without resolving + */ + Z peekModuleName(int index, NameMapper mapper) { + return peekName(buf.getChar(pool.offset(index)), mapper); + } + + /** + * Get a module symbol from the pool at given index. + */ + ModuleSymbol getModule(int index) { + return pool.readIfNeeded(index); + } + + /** + * Get a module symbol from the pool at given index. + */ + PackageSymbol getPackage(int index) { + return pool.readIfNeeded(index); + } + + /** + * Peek a name from the pool at given index without resolving. + */ + Z peekName(int index, Name.NameMapper mapper) { + return getUtf8(index, mapper); + } + + /** + * Get a name from the pool at given index. + */ + Name getName(int index) { + return pool.readIfNeeded(index); + } + + /** + * Get a type from the pool at given index. + */ + Type getType(int index) { + return getName(index).map(reader::sigToType); + } + + /** + * Get a name and type pair from the pool at given index. + */ + NameAndType getNameAndType(int index) { + return pool.readIfNeeded(index); + } + + /** + * Get a class symbol from the pool at given index. + */ + Object getConstant(int index) { + return pool.readIfNeeded(index); + } + + boolean hasTag(int index, int tag) { + return pool.tag(index) == tag; + } + + private Z getUtf8(int index, NameMapper mapper) { + int tag = pool.tag(index); + if (tag == CONSTANT_Utf8) { + int offset = pool.offset(index); + int len = pool.poolbuf.getChar(offset); + return mapper.map(pool.poolbuf.elems, offset + 2, len); + } else { + throw new AssertionError("Unexpected constant tag: " + tag); + } + } + + private Object resolve(ByteBuffer poolbuf, int tag, int offset) { + switch (tag) { + case CONSTANT_Utf8: { + int len = poolbuf.getChar(offset); + return names.fromUtf(poolbuf.elems, offset + 2, len); + } + case CONSTANT_Class: { + int index = poolbuf.getChar(offset); + Name name = names.fromUtf(getName(index).map(ClassFile::internalize)); + return syms.enterClass(reader.currentModule, name); + } + case CONSTANT_NameandType: { + Name name = getName(poolbuf.getChar(offset)); + Type type = getType(poolbuf.getChar(offset + 2)); + return new NameAndType(name, type); + } + case CONSTANT_Integer: + return poolbuf.getInt(offset); + case CONSTANT_Float: + return poolbuf.getFloat(offset); + case CONSTANT_Long: + return poolbuf.getLong(offset); + case CONSTANT_Double: + return poolbuf.getDouble(offset); + case CONSTANT_String: + return getName(poolbuf.getChar(offset)).toString(); + case CONSTANT_Package: { + Name name = getName(poolbuf.getChar(offset)); + return syms.enterPackage(reader.currentModule, names.fromUtf(internalize(name))); + } + case CONSTANT_Module: { + Name name = getName(poolbuf.getChar(offset)); + return syms.enterModule(name); + } + default: + throw new AssertionError("Unexpected constant tag: " + tag); + } + } + + /** + * Parse all constant pool entries, and keep track of their offsets. For performance and laziness + * reasons, it would be unwise to eagerly turn all pool entries into corresponding javac + * entities. First, not all entries are actually going to be read/used by javac; secondly, + * there are cases where creating a symbol too early might result in issues (hence methods like + * {@link PoolReader#peekClassName(int, NameMapper)}. + */ + int readPool(ByteBuffer poolbuf, int offset) { + int poolSize = poolbuf.getChar(offset); + int index = 1; + offset += 2; + int[] offsets = new int[poolSize]; + while (index < poolSize) { + byte tag = poolbuf.getByte(offset++); + offsets[index] = offset; + switch (tag) { + case CONSTANT_Utf8: { + int len = poolbuf.getChar(offset); + offset += 2 + len; + break; + } + case CONSTANT_Class: + case CONSTANT_String: + case CONSTANT_Module: + case CONSTANT_Package: + case CONSTANT_MethodType: + offset += 2; + break; + case CONSTANT_MethodHandle: + offset += 3; + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameandType: + case CONSTANT_Integer: + case CONSTANT_Float: + case CONSTANT_Dynamic: + case CONSTANT_InvokeDynamic: + offset += 4; + break; + case CONSTANT_Long: + case CONSTANT_Double: + offset += 8; + break; + default: + throw reader.badClassFile("bad.const.pool.tag.at", + Byte.toString(tag), + Integer.toString(offset - 1)); + } + index += sizeof(tag); + } + pool = new ImmutablePoolHelper(poolbuf, offsets); + return offset; + } + + private int sizeof(int tag) { + switch (tag) { + case ClassFile.CONSTANT_Double: case ClassFile.CONSTANT_Long: + return 2; + default: + return 1; + } + } + + class ImmutablePoolHelper { + + final Object[] values; + final int[] offsets; + final ByteBuffer poolbuf; + + public ImmutablePoolHelper(ByteBuffer poolbuf, int[] offsets) { + this.offsets = offsets; + this.values = new Object[offsets.length]; + this.poolbuf = poolbuf; + } + + private int checkIndex(int index) { + if (index <= 0 || index >= offsets.length) { + //pool index is outside valid range. + throw reader.badClassFile("bad.const.pool.index", reader.currentClassFile, + index, offsets.length); + } else { + return index; + } + } + + int offset(int index) { + return offsets[checkIndex(index)]; + } + + @SuppressWarnings("unchecked") +

    P readIfNeeded(int index) { + Object v = values[checkIndex(index)]; + if (v != null) { + return (P)v; + } else { + P p = (P)resolve(poolbuf, tag(index), offset(index)); + values[index] = p; + return p; + } + } + + int tag(int index) { + return poolbuf.elems[offset(index) - 1]; + } + } +} diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import com.sun.tools.javac.code.Kinds.Kind; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; +import com.sun.tools.javac.code.Symbol.MethodHandleSymbol; +import com.sun.tools.javac.code.Symbol.ModuleSymbol; +import com.sun.tools.javac.code.Symbol.PackageSymbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow; +import com.sun.tools.javac.jvm.ClassWriter.StringOverflow; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant; +import com.sun.tools.javac.jvm.PoolConstant.Dynamic; +import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey; +import com.sun.tools.javac.jvm.PoolConstant.NameAndType; +import com.sun.tools.javac.util.ByteBuffer; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; + +import static com.sun.tools.javac.code.Kinds.Kind.TYP; +import static com.sun.tools.javac.code.TypeTag.ARRAY; +import static com.sun.tools.javac.code.TypeTag.CLASS; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class; +import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType; +import static com.sun.tools.javac.jvm.ClassFile.externalize; + +/** + * Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities + * into the constant pool. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class PoolWriter { + + /** Max number of constant pool entries. */ + public static final int MAX_ENTRIES = 0xFFFF; + + /** Max number of char in a string constant. */ + public static final int MAX_STRING_LENGTH = 0xFFFF; + + private static final int POOL_BUF_SIZE = 0x7fff; + + private final Types types; + + private final Names names; + + /** Pool helper **/ + final WriteablePoolHelper pool; + + /** Sole signature generator */ + final SharedSignatureGenerator signatureGen; + + /** The inner classes to be written, as an ordered set (enclosing first). */ + LinkedHashSet innerClasses = new LinkedHashSet<>(); + + /** The list of entries in the BootstrapMethods attribute. */ + Map bootstrapMethods = new LinkedHashMap<>(); + + public PoolWriter(Types types, Names names) { + this.types = types; + this.names = names; + this.signatureGen = new SharedSignatureGenerator(types); + this.pool = new WriteablePoolHelper(); + } + + /** + * Puts a class symbol into the pool and return its index. + */ + int putClass(ClassSymbol csym) { + return putClass(csym.type); + } + + /** + * Puts a type into the pool and return its index. The type could be either a class, a type variable + * or an array type. + */ + int putClass(Type t) { + return pool.writeIfNeeded(types.erasure(t)); + } + + /** + * Puts a member reference into the constant pool. Valid members are either field or method symbols. + */ + int putMember(Symbol s) { + return pool.writeIfNeeded(s); + } + + /** + * Puts a dynamic reference into the constant pool and return its index. + */ + int putDynamic(DynamicMethodSymbol d) { + return pool.writeIfNeeded(d); + } + + /** + * Puts a field or method descriptor into the constant pool and return its index. + */ + int putDescriptor(Type t) { + return putName(typeSig(types.erasure(t))); + } + + /** + * Puts a field or method descriptor into the constant pool and return its index. + */ + int putDescriptor(Symbol s) { + return putDescriptor(descriptorType(s)); + } + + /** + * Puts a signature (see {@code Signature} attribute in JVMS 4.4) into the constant pool and + * return its index. + */ + int putSignature(Symbol s) { + if (s.kind == TYP) { + return putName(classSig(s.type)); + } else { + return putName(typeSig(s.type)); + } + } + + /** + * Puts a constant value into the pool and return its index. Supported values are int, float, long, + * double and String. + */ + int putConstant(Object o) { + if (o instanceof Integer) { + return putConstant(LoadableConstant.Int((int)o)); + } else if (o instanceof Float) { + return putConstant(LoadableConstant.Float((float)o)); + } else if (o instanceof Long) { + return putConstant(LoadableConstant.Long((long)o)); + } else if (o instanceof Double) { + return putConstant(LoadableConstant.Double((double)o)); + } else if (o instanceof String) { + return putConstant(LoadableConstant.String((String)o)); + } else { + throw new AssertionError("unexpected constant: " + o); + } + } + + /** + * Puts a constant into the pool and return its index. + */ + int putConstant(LoadableConstant c) { + switch (c.poolTag()) { + case CONSTANT_Class: + return putClass((Type)c); + case CONSTANT_MethodType: + return pool.writeIfNeeded(types.erasure((Type)c)); + default: + return pool.writeIfNeeded(c); + } + } + + int putName(Name name) { + return pool.writeIfNeeded(name); + } + + /** + * Puts a name and type pair into the pool and returns its index. + */ + int putNameAndType(Symbol s) { + return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s))); + } + + /** + * Puts a package entry into the pool and returns its index. + */ + int putPackage(PackageSymbol pkg) { + return pool.writeIfNeeded(pkg); + } + + /** + * Puts a module entry into the pool and returns its index. + */ + int putModule(ModuleSymbol mod) { + return pool.writeIfNeeded(mod); + } + + /** + * Enter an inner class into the `innerClasses' set. + */ + void enterInner(ClassSymbol c) { + if (c.type.isCompound()) { + throw new AssertionError("Unexpected intersection type: " + c.type); + } + c.complete(); + if (c.owner.enclClass() != null && !innerClasses.contains(c)) { + enterInner(c.owner.enclClass()); + innerClasses.add(c); + } + } + + /** + * Create a new Utf8 entry representing a descriptor for given (member) symbol. + */ + private Type descriptorType(Symbol s) { + return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types); + } + + private int makeBoostrapEntry(Dynamic dynamic) { + BsmKey bsmKey = dynamic.bsmKey(types); + + // Figure out the index for existing BSM; create a new BSM if no key + Integer index = bootstrapMethods.get(bsmKey); + if (index == null) { + index = bootstrapMethods.size(); + bootstrapMethods.put(bsmKey, index); + } + + return index; + } + + /** + * Write pool contents into given byte buffer. + */ + void writePool(OutputStream out) throws IOException, PoolOverflow { + if (pool.overflowString != null) { + throw new StringOverflow(pool.overflowString); + } + int size = size(); + if (size > MAX_ENTRIES) { + throw new PoolOverflow(); + } + out.write(size >> 8); + out.write(size); + out.write(pool.poolbuf.elems, 0, pool.poolbuf.length); + } + + /** + * Signature Generation + */ + class SharedSignatureGenerator extends Types.SignatureGenerator { + + /** + * An output buffer for type signatures. + */ + ByteBuffer sigbuf = new ByteBuffer(); + + SharedSignatureGenerator(Types types) { + super(types); + } + + /** + * Assemble signature of given type in string buffer. + * Check for uninitialized types before calling the general case. + */ + @Override + public void assembleSig(Type type) { + switch (type.getTag()) { + case UNINITIALIZED_THIS: + case UNINITIALIZED_OBJECT: + // we don't yet have a spec for uninitialized types in the + // local variable table + assembleSig(types.erasure(((UninitializedType)type).qtype)); + break; + default: + super.assembleSig(type); + } + } + + @Override + protected void append(char ch) { + sigbuf.appendByte(ch); + } + + @Override + protected void append(byte[] ba) { + sigbuf.appendBytes(ba); + } + + @Override + protected void append(Name name) { + sigbuf.appendName(name); + } + + @Override + protected void classReference(ClassSymbol c) { + enterInner(c); + } + + protected void reset() { + sigbuf.reset(); + } + + protected Name toName() { + return sigbuf.toName(names); + } + } + + class WriteablePoolHelper { + + /** Pool entries. */ + private final Map keysToPos = new HashMap<>(64); + + final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE); + + int currentIndex = 1; + + ArrayDeque todo = new ArrayDeque<>(); + + String overflowString = null; + + private

    int writeIfNeeded(P p) { + Object key = p.poolKey(types); + Integer index = keysToPos.get(key); + if (index == null) { + keysToPos.put(key, index = currentIndex++); + boolean first = todo.isEmpty(); + todo.addLast(p); + if (first) { + while (!todo.isEmpty()) { + writeConstant(todo.peekFirst()); + todo.removeFirst(); + } + } + } + return index; + } + + void writeConstant(PoolConstant c) { + int tag = c.poolTag(); + switch (tag) { + case ClassFile.CONSTANT_Class: { + Type ct = (Type)c; + Name name = ct.hasTag(ARRAY) ? + typeSig(ct) : + names.fromUtf(externalize(ct.tsym.flatName())); + poolbuf.appendByte(tag); + poolbuf.appendChar(putName(name)); + if (ct.hasTag(CLASS)) { + enterInner((ClassSymbol)ct.tsym); + } + break; + } + case ClassFile.CONSTANT_Utf8: { + Name name = (Name)c; + poolbuf.appendByte(tag); + byte[] bs = name.toUtf(); + poolbuf.appendChar(bs.length); + poolbuf.appendBytes(bs, 0, bs.length); + if (overflowString == null && bs.length > MAX_STRING_LENGTH) { + //report error only once + overflowString = new String(bs); + } + break; + } + case ClassFile.CONSTANT_InterfaceMethodref: + case ClassFile.CONSTANT_Methodref: + case ClassFile.CONSTANT_Fieldref: { + Symbol sym = (Symbol)c; + poolbuf.appendByte(tag); + poolbuf.appendChar(putClass((ClassSymbol)sym.owner)); + poolbuf.appendChar(putNameAndType(sym)); + break; + } + case ClassFile.CONSTANT_Package: { + PackageSymbol pkg = (PackageSymbol)c; + Name pkgName = names.fromUtf(externalize(pkg.flatName())); + poolbuf.appendByte(tag); + poolbuf.appendChar(putName(pkgName)); + break; + } + case ClassFile.CONSTANT_Module: { + ModuleSymbol mod = (ModuleSymbol)c; + int modName = putName(mod.name); + poolbuf.appendByte(mod.poolTag()); + poolbuf.appendChar(modName); + break; + } + case ClassFile.CONSTANT_Integer: + poolbuf.appendByte(tag); + poolbuf.appendInt((int)((BasicConstant)c).data); + break; + case ClassFile.CONSTANT_Float: + poolbuf.appendByte(tag); + poolbuf.appendFloat((float)((BasicConstant)c).data); + break; + case ClassFile.CONSTANT_Long: + currentIndex++; + poolbuf.appendByte(tag); + poolbuf.appendLong((long)((BasicConstant)c).data); + break; + case ClassFile.CONSTANT_Double: + currentIndex++; + poolbuf.appendByte(tag); + poolbuf.appendDouble((double)((BasicConstant)c).data); + break; + case ClassFile.CONSTANT_MethodHandle: { + MethodHandleSymbol h = (MethodHandleSymbol)c; + poolbuf.appendByte(tag); + poolbuf.appendByte(h.referenceKind()); + poolbuf.appendChar(putMember(h.baseSymbol())); + break; + } + case ClassFile.CONSTANT_MethodType: { + Type.MethodType mt = (Type.MethodType)c; + poolbuf.appendByte(tag); + poolbuf.appendChar(putDescriptor(mt.baseType())); + break; + } + case ClassFile.CONSTANT_String: { + Name utf = names.fromString((String)((BasicConstant)c).data); + poolbuf.appendByte(tag); + poolbuf.appendChar(putName(utf)); + break; + } + case ClassFile.CONSTANT_NameandType: { + NameAndType nt = (NameAndType)c; + poolbuf.appendByte(tag); + poolbuf.appendChar(putName(nt.name)); + poolbuf.appendChar(putDescriptor(nt.type)); + break; + } + case ClassFile.CONSTANT_InvokeDynamic: { + DynamicMethodSymbol d = (DynamicMethodSymbol)c; + poolbuf.appendByte(tag); + poolbuf.appendChar(makeBoostrapEntry(d)); + poolbuf.appendChar(putNameAndType(d)); + break; + } + default: + throw new AssertionError("Unexpected constant tag: " + tag); + } + } + + void reset() { + keysToPos.clear(); + currentIndex = 1; + todo.clear(); + overflowString = null; + poolbuf.reset(); + } + } + + int size() { + return pool.currentIndex; + } + + /** + * Return signature of given type + */ + private Name typeSig(Type type) { + signatureGen.reset(); + signatureGen.assembleSig(type); + return signatureGen.toName(); + } + + private Name classSig(Type t) { + signatureGen.reset(); + List typarams = t.getTypeArguments(); + if (typarams.nonEmpty()) { + signatureGen.assembleParamsSig(typarams); + } + signatureGen.assembleSig(types.supertype(t)); + for (Type i : types.interfaces(t)) + signatureGen.assembleSig(i); + return signatureGen.toName(); + } + + void reset() { + innerClasses.clear(); + bootstrapMethods.clear(); + pool.reset(); + } +} diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java Fri Apr 19 08:00:42 2019 -0400 @@ -26,7 +26,9 @@ package com.sun.tools.javac.jvm; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.comp.Resolve; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeMaker; @@ -222,7 +224,7 @@ private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) { JCDiagnostic.DiagnosticPosition pos = tree.pos(); - gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType)); + gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType), syms.stringBuilderType); gen.getCode().emitop0(dup); gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false); return pos; @@ -378,10 +380,9 @@ Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat, syms.noSymbol, - ClassFile.REF_invokeStatic, - (Symbol.MethodSymbol)bsm, + ((MethodSymbol)bsm).asHandle(), indyType, - List.nil().toArray()); + List.nil().toArray(new LoadableConstant[0])); Items.Item item = gen.getItems().makeDynamicItem(dynSym); item.invoke(); @@ -416,7 +417,7 @@ StringBuilder recipe = new StringBuilder(t.size()); ListBuffer dynamicArgs = new ListBuffer<>(); - ListBuffer staticArgs = new ListBuffer<>(); + ListBuffer staticArgs = new ListBuffer<>(); for (JCTree arg : t) { Object constVal = arg.type.constValue(); @@ -431,7 +432,7 @@ String a = arg.type.stringValue(); if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) { recipe.append(TAG_CONST); - staticArgs.add(a); + staticArgs.add(LoadableConstant.String(a)); } else { recipe.append(a); } @@ -463,7 +464,7 @@ } /** Produce the actual invokedynamic call to StringConcatFactory */ - private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List staticArgs, List dynamicArgTypes) { + private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List staticArgs, List dynamicArgTypes) { Type.MethodType indyType = new Type.MethodType(dynamicArgTypes, type, List.nil(), @@ -474,8 +475,8 @@ make.at(pos); ListBuffer constTypes = new ListBuffer<>(); - ListBuffer constants = new ListBuffer<>(); - for (Object t : staticArgs) { + ListBuffer constants = new ListBuffer<>(); + for (LoadableConstant t : staticArgs) { constants.add(t); constTypes.add(syms.stringType); } @@ -495,10 +496,10 @@ Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants, syms.noSymbol, - ClassFile.REF_invokeStatic, - (Symbol.MethodSymbol)bsm, + ((MethodSymbol)bsm).asHandle(), indyType, - List.of(recipe).appendList(constants).toArray()); + List.of(LoadableConstant.String(recipe)) + .appendList(constants).toArray(new LoadableConstant[constants.size()])); Items.Item item = gen.getItems().makeDynamicItem(dynSym); item.invoke(); diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,6 +188,11 @@ private final Context context; + /** + * Support for preview language features. + */ + private final Preview preview; + /** Get the JavacProcessingEnvironment instance for this context. */ public static JavacProcessingEnvironment instance(Context context) { JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class); @@ -236,6 +241,7 @@ enter = Enter.instance(context); initialCompleter = ClassFinder.instance(context).getCompleter(); chk = Check.instance(context); + preview = Preview.instance(context); initProcessorLoader(); } @@ -1675,6 +1681,11 @@ return messages.getCurrentLocale(); } + @DefinedBy(Api.ANNOTATION_PROCESSING) + public boolean isPreviewEnabled() { + return preview.isEnabled(); + } + public Set getSpecifiedPackages() { return specifiedPackages; } diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Apr 19 08:00:42 2019 -0400 @@ -2164,6 +2164,11 @@ bad constant pool entry in {0}\n\ expected {1} at index {2} +# 0: file name, 1: number (constant pool index), 2: number (constant pool size) +compiler.misc.bad.const.pool.index=\ + bad constant pool index in {0}\n\ + index {1} is not within pool size {2}. + # 0: file name, 1: message segment compiler.misc.bad.class.file.header=\ bad class file: {0}\n\ diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java Fri Apr 19 08:00:42 2019 -0400 @@ -147,6 +147,90 @@ appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength()); } + /** Append the content of a given input stream. + */ + public void appendStream(InputStream is) throws IOException { + try { + int start = length; + int initialSize = is.available(); + elems = ArrayUtils.ensureCapacity(elems, length + initialSize); + int r = is.read(elems, start, initialSize); + int bp = start; + while (r != -1) { + bp += r; + elems = ArrayUtils.ensureCapacity(elems, bp); + r = is.read(elems, bp, elems.length - bp); + } + } finally { + try { + is.close(); + } catch (IOException e) { + /* Ignore any errors, as this stream may have already + * thrown a related exception which is the one that + * should be reported. + */ + } + } + } + + /** Extract an integer at position bp from elems. + */ + public int getInt(int bp) { + return + ((elems[bp] & 0xFF) << 24) + + ((elems[bp+1] & 0xFF) << 16) + + ((elems[bp+2] & 0xFF) << 8) + + (elems[bp+3] & 0xFF); + } + + + /** Extract a long integer at position bp from elems. + */ + public long getLong(int bp) { + DataInputStream elemsin = + new DataInputStream(new ByteArrayInputStream(elems, bp, 8)); + try { + return elemsin.readLong(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** Extract a float at position bp from elems. + */ + public float getFloat(int bp) { + DataInputStream elemsin = + new DataInputStream(new ByteArrayInputStream(elems, bp, 4)); + try { + return elemsin.readFloat(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** Extract a double at position bp from elems. + */ + public double getDouble(int bp) { + DataInputStream elemsin = + new DataInputStream(new ByteArrayInputStream(elems, bp, 8)); + try { + return elemsin.readDouble(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** Extract a character at position bp from elems. + */ + public char getChar(int bp) { + return + (char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF)); + } + + public byte getByte(int bp) { + return elems[bp]; + } + /** Reset to zero length. */ public void reset() { diff -r 221a589c52ee -r 4649818834e0 src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java Fri Apr 19 08:00:42 2019 -0400 @@ -25,6 +25,8 @@ package com.sun.tools.javac.util; +import com.sun.tools.javac.jvm.ClassFile; +import com.sun.tools.javac.jvm.PoolConstant; import com.sun.tools.javac.util.DefinedBy.Api; /** An abstraction for internal compiler strings. They are stored in @@ -36,7 +38,7 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -public abstract class Name implements javax.lang.model.element.Name { +public abstract class Name implements javax.lang.model.element.Name, PoolConstant { public final Table table; @@ -52,6 +54,11 @@ return toString().equals(cs.toString()); } + @Override + public int poolTag() { + return ClassFile.CONSTANT_Utf8; + } + /** * {@inheritDoc} */ @@ -188,6 +195,14 @@ */ public abstract int getByteOffset(); + public interface NameMapper { + X map(byte[] bytes, int offset, int len); + } + + public X map(NameMapper mapper) { + return mapper.map(getByteArray(), getByteOffset(), getByteLength()); + } + /** An abstraction for the hash table used to create unique Name instances. */ public static abstract class Table { diff -r 221a589c52ee -r 4649818834e0 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java Fri Apr 19 08:00:42 2019 -0400 @@ -1137,20 +1137,79 @@ private static long nativeKeyWrapperKeyID = 0; private static CK_MECHANISM nativeKeyWrapperMechanism = null; + private static long nativeKeyWrapperRefCount = 0; + private static Session nativeKeyWrapperSession = null; private final P11Key p11Key; private final byte[] nativeKeyInfo; + private boolean wrapperKeyUsed; // destroyed and recreated when refCount toggles to 1 private long keyID; - private boolean isTokenObject; - // phantom reference notification clean up for session keys private SessionKeyRef ref; private int refCount; + private static void createNativeKeyWrapper(Token token) + throws PKCS11Exception { + assert(nativeKeyWrapperKeyID == 0); + assert(nativeKeyWrapperRefCount == 0); + assert(nativeKeyWrapperSession == null); + // Create a global wrapping/unwrapping key + CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes(O_GENERATE, + CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3)}); + Session s = null; + try { + s = token.getObjSession(); + nativeKeyWrapperKeyID = token.p11.C_GenerateKey( + s.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), + wrappingAttributes); + nativeKeyWrapperSession = s; + nativeKeyWrapperSession.addObject(); + byte[] iv = new byte[16]; + JCAUtil.getSecureRandom().nextBytes(iv); + nativeKeyWrapperMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + + private static void deleteNativeKeyWrapper() { + Token token = nativeKeyWrapperSession.token; + if (token.isValid()) { + Session s = null; + try { + s = token.getOpSession(); + token.p11.C_DestroyObject(s.id(), nativeKeyWrapperKeyID); + nativeKeyWrapperSession.removeObject(); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + nativeKeyWrapperKeyID = 0; + nativeKeyWrapperMechanism = null; + nativeKeyWrapperSession = null; + } + + static void decWrapperKeyRef() { + synchronized(NativeKeyHolder.class) { + assert(nativeKeyWrapperKeyID != 0); + assert(nativeKeyWrapperRefCount > 0); + nativeKeyWrapperRefCount--; + if (nativeKeyWrapperRefCount == 0) { + deleteNativeKeyWrapper(); + } + } + } + NativeKeyHolder(P11Key p11Key, long keyID, Session keySession, boolean extractKeyInfo, boolean isTokenObject) { this.p11Key = p11Key; @@ -1160,35 +1219,23 @@ if (isTokenObject) { this.ref = null; } else { - this.ref = new SessionKeyRef(p11Key, keyID, keySession); - // Try extracting key info, if any error, disable it Token token = p11Key.token; if (extractKeyInfo) { try { - if (p11Key.sensitive && nativeKeyWrapperKeyID == 0) { + if (p11Key.sensitive) { + // p11Key native key information has to be wrapped synchronized(NativeKeyHolder.class) { - // Create a global wrapping/unwrapping key - CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes - (O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { - new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), - new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3), - }); - Session wrappingSession = null; - try { - wrappingSession = token.getObjSession(); - nativeKeyWrapperKeyID = token.p11.C_GenerateKey - (wrappingSession.id(), - new CK_MECHANISM(CKM_AES_KEY_GEN), - wrappingAttributes); - byte[] iv = new byte[16]; - JCAUtil.getSecureRandom().nextBytes(iv); - nativeKeyWrapperMechanism = new CK_MECHANISM - (CKM_AES_CBC_PAD, iv); - } catch (PKCS11Exception e) { - // best effort - } finally { - token.releaseSession(wrappingSession); + if (nativeKeyWrapperKeyID == 0) { + createNativeKeyWrapper(token); + } + // If a wrapper-key was successfully created or + // already exists, increment its reference + // counter to keep it alive while native key + // information is being held. + if (nativeKeyWrapperKeyID != 0) { + nativeKeyWrapperRefCount++; + wrapperKeyUsed = true; } } } @@ -1196,7 +1243,8 @@ try { opSession = token.getOpSession(); ki = p11Key.token.p11.getNativeKeyInfo(opSession.id(), - keyID, nativeKeyWrapperKeyID, nativeKeyWrapperMechanism); + keyID, nativeKeyWrapperKeyID, + nativeKeyWrapperMechanism); } catch (PKCS11Exception e) { // best effort } finally { @@ -1206,6 +1254,8 @@ // best effort } } + this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed, + keySession); } this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki); } @@ -1222,18 +1272,15 @@ throw new RuntimeException( "Error: null keyID with non-zero refCount " + cnt); } - if (this.ref != null) { - throw new RuntimeException( - "Error: null keyID with non-null session ref"); - } Token token = p11Key.token; // Create keyID using nativeKeyInfo Session session = null; try { session = token.getObjSession(); this.keyID = token.p11.createNativeKey(session.id(), - nativeKeyInfo, nativeKeyWrapperKeyID, nativeKeyWrapperMechanism); - this.ref = new SessionKeyRef(p11Key, this.keyID, session); + nativeKeyInfo, nativeKeyWrapperKeyID, + nativeKeyWrapperMechanism); + this.ref.registerNativeKey(this.keyID, session); } catch (PKCS11Exception e) { this.refCount--; throw new ProviderException("Error recreating native key", e); @@ -1263,12 +1310,9 @@ throw new RuntimeException("ERROR: null keyID can't be destroyed"); } - if (this.ref == null) { - throw new RuntimeException("ERROR: null session ref can't be disposed"); - } // destroy this.keyID = 0; - this.ref = this.ref.dispose(); + this.ref.removeNativeKey(); } else { if (cnt < 0) { // should never happen as we start count at 1 and pair get/release calls @@ -1285,12 +1329,11 @@ * otherwise the key maybe cleared before other objects which * still use these keys during finalization such as SSLSocket. */ -final class SessionKeyRef extends PhantomReference - implements Comparable { +final class SessionKeyRef extends PhantomReference { private static ReferenceQueue refQueue = new ReferenceQueue(); - private static Set refList = - Collections.synchronizedSortedSet(new TreeSet()); + private static Set refSet = + Collections.synchronizedSet(new HashSet()); static ReferenceQueue referenceQueue() { return refQueue; @@ -1307,47 +1350,69 @@ } // handle to the native key and the session it is generated under - private final long keyID; - private final Session session; + private long keyID; + private Session session; + private boolean wrapperKeyUsed; - SessionKeyRef(P11Key p11Key, long keyID, Session session) { + SessionKeyRef(P11Key p11Key, long keyID, boolean wrapperKeyUsed, + Session session) { super(p11Key, refQueue); if (session == null) { throw new ProviderException("key must be associated with a session"); } - this.keyID = keyID; - this.session = session; - this.session.addObject(); + registerNativeKey(keyID, session); + this.wrapperKeyUsed = wrapperKeyUsed; - refList.add(this); + refSet.add(this); drainRefQueueBounded(); } - SessionKeyRef dispose() { - Token token = session.token; - // If the token is still valid, try to remove the key object - if (token.isValid()) { - Session s = null; - try { - s = token.getOpSession(); - token.p11.C_DestroyObject(s.id(), keyID); - } catch (PKCS11Exception e) { - // best effort - } finally { - token.releaseSession(s); - } - } - refList.remove(this); - this.clear(); - session.removeObject(); - return null; + void registerNativeKey(long newKeyID, Session newSession) { + assert(newKeyID != 0); + assert(newSession != null); + updateNativeKey(newKeyID, newSession); + } + + void removeNativeKey() { + assert(session != null); + updateNativeKey(0, null); } - public int compareTo(SessionKeyRef other) { - if (this.keyID == other.keyID) { - return 0; + private void updateNativeKey(long newKeyID, Session newSession) { + if (newKeyID == 0) { + assert(newSession == null); + Token token = session.token; + // If the token is still valid, try to remove the key object + if (token.isValid()) { + Session s = null; + try { + s = token.getOpSession(); + token.p11.C_DestroyObject(s.id(), this.keyID); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + session.removeObject(); } else { - return (this.keyID < other.keyID) ? -1 : 1; + newSession.addObject(); } + keyID = newKeyID; + session = newSession; + } + + // Called when the GC disposes a p11Key + void dispose() { + if (wrapperKeyUsed) { + // Wrapper-key no longer needed for + // p11Key native key information + NativeKeyHolder.decWrapperKeyRef(); + } + if (keyID != 0) { + removeNativeKey(); + } + refSet.remove(this); + this.clear(); } } diff -r 221a589c52ee -r 4649818834e0 src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c Fri Apr 19 08:00:42 2019 -0400 @@ -308,7 +308,7 @@ *(CK_BBOOL*)(((CK_ATTRIBUTE_PTR)(((CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes) +sensitiveAttributePosition))->pValue) == CK_TRUE) { // Key is sensitive. Need to extract it wrapped. - if (jWrappingKeyHandle != -1) { + if (jWrappingKeyHandle != 0) { jMechanismToCKMechanism(env, jWrappingMech, &ckMechanism); rv = (*ckpFunctions->C_WrapKey)(ckSessionHandle, &ckMechanism, @@ -351,6 +351,7 @@ goto cleanup; } } else { + ckAssertReturnValueOK(env, CKR_KEY_HANDLE_INVALID); goto cleanup; } returnValue = nativeKeyInfoWrappedKeyArray; diff -r 221a589c52ee -r 4649818834e0 src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java Fri Apr 19 08:00:42 2019 -0400 @@ -89,7 +89,7 @@ * .withNamespace(StandardNamespace.PROPERTY) * .named("color"); * - *

    Operations on multiple namespaces

    + *

    Operations on multiple namespaces

    * If multiple namespaces are specified, the namespaces are treated as * alternatives to each other in order of preference. The semantics of * such operation is "first applicable". diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.formats.html; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; - -import javax.lang.model.element.ModuleElement; -import javax.lang.model.element.PackageElement; - -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.DocPath; - -/** - * Abstract class to generate the module overview files. - * - *

    This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @author Bhavesh Patel - */ -public abstract class AbstractModuleIndexWriter extends HtmlDocletWriter { - - /** - * Modules to be documented. - */ - protected SortedMap> modules; - - protected Navigation navBar; - - /** - * Constructor. Also initializes the modules variable. - * - * @param configuration The current configuration - * @param filename Name of the module index file to be generated. - */ - public AbstractModuleIndexWriter(HtmlConfiguration configuration, - DocPath filename) { - super(configuration, filename); - modules = configuration.modulePackages; - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path); - } - - /** - * Adds the navigation bar header to the documentation tree. - * - * @param header the document tree to which the navigation bar header will be added - */ - protected abstract void addNavigationBarHeader(Content header); - - /** - * Adds the navigation bar footer to the documentation tree. - * - * @param footer the document tree to which the navigation bar footer will be added - */ - protected abstract void addNavigationBarFooter(Content footer); - - /** - * Adds the overview header to the documentation tree. - * - * @param main the document tree to which the overview header will be added - */ - protected abstract void addOverviewHeader(Content main); - - /** - * Adds the modules list to the documentation tree. - * - * @param main the document tree to which the modules list will be added - */ - protected abstract void addModulesList(Content main); - - /** - * Adds the module packages list to the documentation tree. - * - * @param modules the set of modules - * @param text caption for the table - * @param tableSummary summary for the table - * @param main the document tree to which the modules list will be added - * @param mdle the module being documented - */ - protected abstract void addModulePackagesList(Map> modules, String text, - String tableSummary, Content main, ModuleElement mdle); - - /** - * Generate and prints the contents in the module index file. - * - * @param title the title of the window - * @param description the content for the description META tag - * @throws DocFileIOException if there is a problem building the module index file - */ - protected void buildModuleIndexFile(String title, String description) - throws DocFileIOException { - String windowOverview = resources.getText(title); - Content body = getBody(getWindowTitle(windowOverview)); - Content header = HtmlTree.HEADER(); - addNavigationBarHeader(header); - Content main = HtmlTree.MAIN(); - addOverviewHeader(main); - addIndex(header, main); - addOverview(main); - Content footer = HtmlTree.FOOTER(); - addNavigationBarFooter(footer); - body.add(header); - body.add(main); - body.add(footer); - printHtmlDocument( - configuration.metakeywords.getOverviewMetaKeywords(title, configuration.doctitle), - description, - body); - } - - /** - * Generate and prints the contents in the module packages index file. - * - * @param title the title of the window. - * @param description the content for the description META tag - * @param mdle the name of the module being documented - * @throws DocFileIOException if there is an exception building the module packages index file - */ - protected void buildModulePackagesIndexFile(String title, String description, - ModuleElement mdle) throws DocFileIOException { - String windowOverview = resources.getText(title); - Content body = getBody(getWindowTitle(windowOverview)); - Content header = HtmlTree.HEADER(); - addNavigationBarHeader(header); - Content main = HtmlTree.MAIN(); - addOverviewHeader(main); - addModulePackagesIndex(header, main, mdle); - addOverview(main); - Content footer = HtmlTree.FOOTER(); - addNavigationBarFooter(footer); - body.add(header); - body.add(main); - body.add(footer); - printHtmlDocument( - configuration.metakeywords.getOverviewMetaKeywords(title, configuration.doctitle), - description, - body); - } - - /** - * Default to no overview, override to add overview. - * - * @param main the document tree to which the overview will be added - */ - protected void addOverview(Content main) { } - - /** - * Adds the module index to the documentation tree. - * - * @param header the document tree to which the navigational links will be added - * @param main the document tree to which the modules list will be added - */ - protected void addIndex(Content header, Content main) { - addIndexContents(configuration.modules, "doclet.Module_Summary", - resources.getText("doclet.Member_Table_Summary", - resources.getText("doclet.Module_Summary"), - resources.getText("doclet.modules")), header, main); - } - - /** - * Adds the module packages index to the documentation tree. - * - * @param header the document tree to which the navigational links will be added - * @param main the document tree to which the module packages list will be added - * @param mdle the module being documented - */ - protected void addModulePackagesIndex(Content header, Content main, ModuleElement mdle) { - addModulePackagesIndexContents("doclet.Module_Summary", - resources.getText("doclet.Member_Table_Summary", - resources.getText("doclet.Module_Summary"), - resources.getText("doclet.modules")), header, main, mdle); - } - - /** - * Adds module index contents. Call appropriate methods from - * the sub-classes. Adds it to the body HtmlTree - * - * @param modules the modules to be documented - * @param text string which will be used as the heading - * @param tableSummary summary for the table - * @param header the document tree to which the navigational links will be added - * @param main the document tree to which the modules list will be added - */ - protected void addIndexContents(Collection modules, String text, - String tableSummary, Content header, Content main) { - addModulesList(main); - } - - /** - * Adds module packages index contents. Call appropriate methods from - * the sub-classes. Adds it to the body HtmlTree - * - * @param text string which will be used as the heading - * @param tableSummary summary for the table - * @param header the document tree to which the navigational links will be added - * @param main the document tree to which the module packages list will be added - * @param mdle the module being documented - */ - protected void addModulePackagesIndexContents(String text, - String tableSummary, Content header, Content main, ModuleElement mdle) { - addModulePackagesList(modules, text, tableSummary, main, mdle); - } - - /** - * Adds the doctitle to the documentation tree, if it is specified on the command line. - * - * @param body the document tree to which the title will be added - */ - protected void addConfigurationTitle(Content body) { - if (configuration.doctitle.length() > 0) { - Content title = new RawHtml(configuration.doctitle); - Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, title); - Content div = HtmlTree.DIV(HtmlStyle.header, heading); - body.add(div); - } - } -} diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; +import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; + +/** + * Abstract class to generate the overview files. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + */ +public abstract class AbstractOverviewIndexWriter extends HtmlDocletWriter { + + protected Navigation navBar; + + /** + * Constructs the AbstractOverviewIndexWriter. + * + * @param configuration The current configuration + * @param filename Name of the module index file to be generated. + */ + public AbstractOverviewIndexWriter(HtmlConfiguration configuration, + DocPath filename) { + super(configuration, filename); + this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path); + } + + /** + * Adds the top text (from the -top option), the upper + * navigation bar, and then the title (from the"-title" + * option), at the top of page. + * + * @param header the documentation tree to which the navigation bar header will be added + */ + protected void addNavigationBarHeader(Content header) { + addTop(header); + navBar.setUserHeader(getUserHeaderFooter(true)); + header.add(navBar.getContent(true)); + } + + /** + * Adds the lower navigation bar and the bottom text + * (from the -bottom option) at the bottom of page. + * + * @param footer the documentation tree to which the navigation bar footer will be added + */ + protected void addNavigationBarFooter(Content footer) { + navBar.setUserFooter(getUserHeaderFooter(false)); + footer.add(navBar.getContent(false)); + addBottom(footer); + } + + /** + * Adds the overview summary comment for this documentation. Add one line + * summary at the top of the page and generate a link to the description, + * which is added at the end of this page. + * + * @param main the documentation tree to which the overview header will be added + */ + protected void addOverviewHeader(Content main) { + addConfigurationTitle(main); + if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.setStyle(HtmlStyle.contentContainer); + addOverviewComment(div); + main.add(div); + } + } + + /** + * Adds the overview comment as provided in the file specified by the + * "-overview" option on the command line. + * + * @param htmltree the documentation tree to which the overview comment will + * be added + */ + protected void addOverviewComment(Content htmltree) { + if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { + addInlineComment(configuration.overviewElement, htmltree); + } + } + + /** + * Generate and prints the contents in the index file. + * + * @param title the title of the window + * @param description the content for the description META tag + * @throws DocFileIOException if there is a problem building the package index file + */ + protected void buildOverviewIndexFile(String title, String description) + throws DocFileIOException { + String windowOverview = resources.getText(title); + Content body = getBody(getWindowTitle(windowOverview)); + Content header = HtmlTree.HEADER(); + addNavigationBarHeader(header); + Content main = HtmlTree.MAIN(); + addOverviewHeader(main); + addIndex(main); + Content footer = HtmlTree.FOOTER(); + addNavigationBarFooter(footer); + body.add(header); + body.add(main); + body.add(footer); + printHtmlDocument( + configuration.metakeywords.getOverviewMetaKeywords(title, configuration.doctitle), + description, body); + } + + /** + * Adds the index to the documentation tree. + * + * @param main the document tree to which the packages/modules list will be added + */ + protected abstract void addIndex(Content main); + + /** + * Adds the doctitle to the documentation tree, if it is specified on the command line. + * + * @param body the document tree to which the title will be added + */ + protected void addConfigurationTitle(Content body) { + if (configuration.doctitle.length() > 0) { + Content title = new RawHtml(configuration.doctitle); + Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, + HtmlStyle.title, title); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + body.add(div); + } + } +} diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.formats.html; - -import java.util.*; - -import javax.lang.model.element.PackageElement; - -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.DocPath; - -/** - * Abstract class to generate the overview files. This will be sub-classed to - * generate overview-summary.html. - * - *

    This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @author Atul M Dambalkar - * @author Bhavesh Patel (Modified) - */ -public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { - - /** - * A Set of Packages to be documented. - */ - protected SortedSet packages; - - protected Navigation navBar; - - /** - * Constructor. Also initializes the packages variable. - * - * @param configuration The current configuration - * @param filename Name of the package index file to be generated. - */ - public AbstractPackageIndexWriter(HtmlConfiguration configuration, - DocPath filename) { - super(configuration, filename); - packages = configuration.packages; - this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path); - } - - /** - * Adds the navigation bar header to the documentation tree. - * - * @param header the document tree to which the navigation bar header will be added - */ - protected abstract void addNavigationBarHeader(Content header); - - /** - * Adds the navigation bar footer to the documentation tree. - * - * @param body the document tree to which the navigation bar footer will be added - */ - protected abstract void addNavigationBarFooter(Content body); - - /** - * Adds the overview header to the documentation tree. - * - * @param footer the document tree to which the overview header will be added - */ - protected abstract void addOverviewHeader(Content footer); - - /** - * Adds the packages list to the documentation tree. - * - * @param main the document tree to which the packages list will be added - */ - protected abstract void addPackagesList(Content main); - - /** - * Generate and prints the contents in the package index file. - * - * @param title the title of the window - * @param description the content for the description META tag - * @throws DocFileIOException if there is a problem building the package index file - */ - protected void buildPackageIndexFile(String title, String description) - throws DocFileIOException { - String windowOverview = resources.getText(title); - Content body = getBody(getWindowTitle(windowOverview)); - Content header = HtmlTree.HEADER(); - addNavigationBarHeader(header); - Content main = HtmlTree.MAIN(); - addOverviewHeader(main); - addIndex(header, main); - addOverview(main); - Content footer = HtmlTree.FOOTER(); - addNavigationBarFooter(footer); - body.add(header); - body.add(main); - body.add(footer); - printHtmlDocument( - configuration.metakeywords.getOverviewMetaKeywords(title, configuration.doctitle), - description, body); - } - - /** - * Default to no overview, override to add overview. - * - * @param main the document tree to which the overview will be added - */ - protected void addOverview(Content main) { } - - /** - * Adds the package index to the documentation tree. - * - * @param header the document tree to which the navigation links will be added - * @param main the document tree to which the packages list will be added - */ - protected void addIndex(Content header, Content main) { - addIndexContents(header, main); - } - - /** - * Adds package index contents. Call appropriate methods from - * the sub-classes. Adds it to the body HtmlTree - * - * @param header the document tree to which navigation links will be added - * @param main the document tree to which the packages list will be added - */ - protected void addIndexContents(Content header, Content main) { - if (!packages.isEmpty()) { - HtmlTree htmlTree = HtmlTree.NAV(); - htmlTree.setStyle(HtmlStyle.indexNav); - HtmlTree ul = new HtmlTree(HtmlTag.UL); - addAllClassesLink(ul); - if (configuration.showModules && configuration.modules.size() > 1) { - addAllModulesLink(ul); - } - htmlTree.add(ul); - header.add(htmlTree); - addPackagesList(main); - } - } - - /** - * Adds the doctitle to the documentation tree, if it is specified on the command line. - * - * @param body the document tree to which the title will be added - */ - protected void addConfigurationTitle(Content body) { - if (configuration.doctitle.length() > 0) { - Content title = new RawHtml(configuration.doctitle); - Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, title); - Content div = HtmlTree.DIV(HtmlStyle.header, heading); - body.add(div); - } - } - - /** - * Do nothing. This will be overridden. - * - * @param div the document tree to which the all classes link will be added - */ - protected void addAllClassesLink(Content div) { - } - - /** - * Do nothing. This will be overridden. - * - * @param div the document tree to which the all modules link will be added - */ - protected void addAllModulesLink(Content div) { - } -} diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java Fri Apr 19 08:00:42 2019 -0400 @@ -53,15 +53,22 @@ * * @author Bhavesh Patel */ -public class ModuleIndexWriter extends AbstractModuleIndexWriter { +public class ModuleIndexWriter extends AbstractOverviewIndexWriter { + + /** + * Modules to be documented. + */ + protected SortedSet modules; /** * Construct the ModuleIndexWriter. + * * @param configuration the configuration object * @param filename the name of the generated file */ public ModuleIndexWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); + modules = configuration.modules; } /** @@ -73,46 +80,23 @@ public static void generate(HtmlConfiguration configuration) throws DocFileIOException { DocPath filename = DocPaths.INDEX; ModuleIndexWriter mdlgen = new ModuleIndexWriter(configuration, filename); - mdlgen.buildModuleIndexFile("doclet.Window_Overview_Summary", "module index"); - } - - /** - * Add the module index. - * - * @param header the documentation tree to which the navigational links will be added - * @param main the documentation tree to which the modules list will be added - */ - @Override - protected void addIndex(Content header, Content main) { - addIndexContents(header, main); + mdlgen.buildOverviewIndexFile("doclet.Window_Overview_Summary", "module index"); } /** - * Adds module index contents. + * Adds the list of modules. * - * @param header the document tree to which the navigational links will be added - * @param main the document tree to which the modules list will be added - */ - protected void addIndexContents(Content header, Content main) { - addModulesList(main); - } - - /** - * Add the list of modules. - * - * @param main the content tree to which the module list will be added + * @param main the documentation tree to which the modules list will be added */ @Override - protected void addModulesList(Content main) { + protected void addIndex(Content main) { Map> groupModuleMap - = configuration.group.groupModules(configuration.modules); + = configuration.group.groupModules(modules); if (!groupModuleMap.keySet().isEmpty()) { - String tableSummary = resources.getText("doclet.Member_Table_Summary", - resources.getText("doclet.Module_Summary"), resources.getText("doclet.modules")); - TableHeader header = new TableHeader(contents.moduleLabel, contents.descriptionLabel); + TableHeader tableHeader = new TableHeader(contents.moduleLabel, contents.descriptionLabel); Table table = new Table(HtmlStyle.overviewSummary) - .setHeader(header) + .setHeader(tableHeader) .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) .setDefaultTab(resources.getText("doclet.All_Modules")) .setTabScript(i -> "show(" + i + ");") @@ -126,7 +110,7 @@ } } - for (ModuleElement mdle : configuration.modules) { + for (ModuleElement mdle : modules) { if (!mdle.isUnnamed()) { if (!(configuration.nodeprecated && utils.isDeprecated(mdle))) { Content moduleLinkContent = getModuleLink(mdle, new StringContent(mdle.getQualifiedName().toString())); @@ -145,67 +129,4 @@ } } } - - /** - * Adds the overview summary comment for this documentation. Add one line - * summary at the top of the page and generate a link to the description, - * which is added at the end of this page. - * - * @param main the documentation tree to which the overview header will be added - */ - @Override - protected void addOverviewHeader(Content main) { - addConfigurationTitle(main); - if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { - HtmlTree div = new HtmlTree(HtmlTag.DIV); - div.setStyle(HtmlStyle.contentContainer); - addOverviewComment(div); - main.add(div); - } - } - - /** - * Adds the overview comment as provided in the file specified by the - * "-overview" option on the command line. - * - * @param htmltree the documentation tree to which the overview comment will - * be added - */ - protected void addOverviewComment(Content htmltree) { - if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { - addInlineComment(configuration.overviewElement, htmltree); - } - } - - /** - * Adds the top text (from the -top option), the upper - * navigation bar, and then the title (from the"-title" - * option), at the top of page. - * - * @param header the documentation tree to which the navigation bar header will be added - */ - @Override - protected void addNavigationBarHeader(Content header) { - addTop(header); - navBar.setUserHeader(getUserHeaderFooter(true)); - header.add(navBar.getContent(true)); - } - - /** - * Adds the lower navigation bar and the bottom text - * (from the -bottom option) at the bottom of page. - * - * @param footer the documentation tree to which the navigation bar footer will be added - */ - @Override - protected void addNavigationBarFooter(Content footer) { - navBar.setUserFooter(getUserHeaderFooter(false)); - footer.add(navBar.getContent(false)); - addBottom(footer); - } - - @Override - protected void addModulePackagesList(Map> modules, String text, - String tableSummary, Content main, ModuleElement mdle) { - } } diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java Fri Apr 19 08:00:42 2019 -0400 @@ -52,7 +52,12 @@ * @author Atul M Dambalkar * @author Bhavesh Patel (Modified) */ -public class PackageIndexWriter extends AbstractPackageIndexWriter { +public class PackageIndexWriter extends AbstractOverviewIndexWriter { + + /** + * A Set of Packages to be documented. + */ + protected SortedSet packages; /** * Construct the PackageIndexWriter. Also constructs the grouping @@ -65,6 +70,7 @@ */ public PackageIndexWriter(HtmlConfiguration configuration, DocPath filename) { super(configuration, filename); + packages = configuration.packages; } /** @@ -76,26 +82,16 @@ public static void generate(HtmlConfiguration configuration) throws DocFileIOException { DocPath filename = DocPaths.INDEX; PackageIndexWriter packgen = new PackageIndexWriter(configuration, filename); - packgen.buildPackageIndexFile("doclet.Window_Overview_Summary", "package index"); + packgen.buildOverviewIndexFile("doclet.Window_Overview_Summary", "package index"); } /** - * Depending upon the grouping information and their titles, add - * separate table indices for each package group. + * Adds the packages list to the documentation tree. * - * @param header the documentation tree to which the navigational links will be added * @param main the documentation tree to which the packages list will be added */ @Override - protected void addIndex(Content header, Content main) { - addIndexContents(header, main); - } - - /** - * {@inheritDoc} - */ - @Override - protected void addPackagesList(Content main) { + protected void addIndex(Content main) { Map> groupPackageMap = configuration.group.groupPackages(packages); @@ -134,62 +130,4 @@ } } } - - /** - * Adds the overview summary comment for this documentation. Add one line - * summary at the top of the page and generate a link to the description, - * which is added at the end of this page. - * - * @param main the documentation tree to which the overview header will be added - */ - @Override - protected void addOverviewHeader(Content main) { - addConfigurationTitle(main); - if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { - HtmlTree div = new HtmlTree(HtmlTag.DIV); - div.setStyle(HtmlStyle.contentContainer); - addOverviewComment(div); - main.add(div); - } - } - - /** - * Adds the overview comment as provided in the file specified by the - * "-overview" option on the command line. - * - * @param htmltree the documentation tree to which the overview comment will - * be added - */ - protected void addOverviewComment(Content htmltree) { - if (!utils.getFullBody(configuration.overviewElement).isEmpty()) { - addInlineComment(configuration.overviewElement, htmltree); - } - } - - /** - * Adds the top text (from the -top option), the upper - * navigation bar, and then the title (from the"-title" - * option), at the top of page. - * - * @param header the documentation tree to which the navigation bar header will be added - */ - @Override - protected void addNavigationBarHeader(Content header) { - addTop(header); - navBar.setUserHeader(getUserHeaderFooter(true)); - header.add(navBar.getContent(true)); - } - - /** - * Adds the lower navigation bar and the bottom text - * (from the -bottom option) at the bottom of page. - * - * @param footer the documentation tree to which the navigation bar footer will be added - */ - @Override - protected void addNavigationBarFooter(Content footer) { - navBar.setUserFooter(getUserHeaderFooter(false)); - footer.add(navBar.getContent(false)); - addBottom(footer); - } } diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties Fri Apr 19 08:00:42 2019 -0400 @@ -98,7 +98,6 @@ doclet.From=From doclet.Uses_Summary=Uses doclet.Provides_Summary=Provides -doclet.Module_Summary=Module Summary doclet.Interface_Summary=Interface Summary doclet.Annotation_Types_Summary=Annotation Types Summary doclet.Enum_Summary=Enum Summary diff -r 221a589c52ee -r 4649818834e0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Fri Apr 19 08:00:42 2019 -0400 @@ -374,7 +374,7 @@ // locale, doclet and maybe taglet, needs to be determined first try { - docletClass = preprocess(fileManager, options); + doclet = preprocess(fileManager, options); } catch (ToolException te) { if (!te.result.isOK()) { if (te.message != null) { @@ -393,24 +393,6 @@ dumpStack(t == null ? oe : t); return oe.result; } - if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { - // no need to dispatch to old, safe to init now - initMessager(); - messager.setLocale(locale); - try { - Object o = docletClass.getConstructor().newInstance(); - doclet = (Doclet) o; - } catch (ReflectiveOperationException exc) { - if (apiMode) { - throw new ClientCodeException(exc); - } - error("main.could_not_instantiate_class", docletClass.getName()); - return ERROR; - } - } else { - error("main.not_a_doclet", docletClass.getName()); - return ERROR; - } Result result = OK; try { @@ -649,7 +631,7 @@ return idx; } - private Class preprocess(JavaFileManager jfm, + private Doclet preprocess(JavaFileManager jfm, List argv) throws ToolException, OptionException { // doclet specifying arguments String userDocletPath = null; @@ -706,71 +688,77 @@ } } - // Step 2: a doclet is provided, nothing more to do. - if (docletClass != null) { - return docletClass; - } // Step 3: doclet name specified ? if so find a ClassLoader, // and load it. - if (userDocletName != null) { - ClassLoader cl = classLoader; - if (cl == null) { - if (!fileManager.hasLocation(DOCLET_PATH)) { - List paths = new ArrayList<>(); - if (userDocletPath != null) { - for (String pathname : userDocletPath.split(File.pathSeparator)) { - paths.add(new File(pathname)); + if(docletClass == null) { + if (userDocletName != null) { + ClassLoader cl = classLoader; + if (cl == null) { + if (!fileManager.hasLocation(DOCLET_PATH)) { + List paths = new ArrayList<>(); + if (userDocletPath != null) { + for (String pathname : userDocletPath.split(File.pathSeparator)) { + paths.add(new File(pathname)); + } + } + try { + ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); + } catch (IOException ioe) { + if (apiMode) { + throw new IllegalArgumentException("Could not set location for " + + userDocletPath, ioe); + } + String text = messager.getText("main.doclet_could_not_set_location", + userDocletPath); + throw new ToolException(CMDERR, text, ioe); } } - try { - ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); - } catch (IOException ioe) { + cl = fileManager.getClassLoader(DOCLET_PATH); + if (cl == null) { + // despite doclet specified on cmdline no classloader found! if (apiMode) { - throw new IllegalArgumentException("Could not set location for " + - userDocletPath, ioe); + throw new IllegalArgumentException("Could not obtain classloader to load " + + + userDocletPath); } - String text = messager.getText("main.doclet_could_not_set_location", - userDocletPath); - throw new ToolException(CMDERR, text, ioe); + String text = messager.getText("main.doclet_no_classloader_found", + userDocletName); + throw new ToolException(CMDERR, text); } } - cl = fileManager.getClassLoader(DOCLET_PATH); - if (cl == null) { - // despite doclet specified on cmdline no classloader found! - if (apiMode) { - throw new IllegalArgumentException("Could not obtain classloader to load " - + userDocletPath); - } - String text = messager.getText("main.doclet_no_classloader_found", - userDocletName); - throw new ToolException(CMDERR, text); - } - } - try { - return cl.loadClass(userDocletName); - } catch (ClassNotFoundException cnfe) { - if (apiMode) { - throw new IllegalArgumentException("Cannot find doclet class " + userDocletName, - cnfe); - } - String text = messager.getText("main.doclet_class_not_found", userDocletName); - throw new ToolException(CMDERR, text, cnfe); + docletClass = loadDocletClass(userDocletName, cl); + } else if (docletName != null){ + docletClass = loadDocletClass(docletName, getClass().getClassLoader()); + } else { + docletClass = StdDoclet; } } - // Step 4: we have a doclet, try loading it - if (docletName != null) { - return loadDocletClass(docletName); + if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { + // no need to dispatch to old, safe to init now + initMessager(); + messager.setLocale(locale); + try { + Object o = docletClass.getConstructor().newInstance(); + doclet = (Doclet) o; + } catch (ReflectiveOperationException exc) { + if (apiMode) { + throw new ClientCodeException(exc); + } + String text = messager.getText("main.could_not_instantiate_class", docletClass.getName()); + throw new ToolException(ERROR, text); + } + } else { + String text = messager.getText("main.not_a_doclet", docletClass.getName()); + throw new ToolException(ERROR, text); } - - // finally - return StdDoclet; + return doclet; } - private Class loadDocletClass(String docletName) throws ToolException { + private Class loadDocletClass(String docletName, ClassLoader classLoader) throws ToolException { try { - return Class.forName(docletName, true, getClass().getClassLoader()); + return classLoader == null ? Class.forName(docletName) : classLoader.loadClass(docletName); } catch (ClassNotFoundException cnfe) { if (apiMode) { throw new IllegalArgumentException("Cannot find doclet class " + docletName); diff -r 221a589c52ee -r 4649818834e0 src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java --- a/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.tools.jcmd; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.List; @@ -121,15 +122,16 @@ if (line.trim().equals("stop")) { break; } - try (InputStream in = hvm.executeJCmd(line);) { + try (InputStream in = hvm.executeJCmd(line); + InputStreamReader isr = new InputStreamReader(in, "UTF-8")) { // read to EOF and just print output - byte b[] = new byte[256]; + char c[] = new char[256]; int n; boolean messagePrinted = false; do { - n = in.read(b); + n = isr.read(c); if (n > 0) { - String s = new String(b, 0, n, "UTF-8"); + String s = new String(c, 0, n); System.out.print(s); messagePrinted = true; } diff -r 221a589c52ee -r 4649818834e0 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NameCodec.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NameCodec.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NameCodec.java Fri Apr 19 08:00:42 2019 -0400 @@ -39,11 +39,11 @@ * to nashorn module. *

    * - *

    Comment from BytecodeName class reproduced here:

    + *

    Comment from BytecodeName class reproduced here:

    * * Includes universal mangling rules for the JVM. * - *

    Avoiding Dangerous Characters

    + *

    Avoiding Dangerous Characters

    * *

    * The JVM defines a very small set of characters which are illegal @@ -74,7 +74,7 @@ * but traditional in the proposed role. * *

    - *

    Replacement Characters

    + *

    Replacement Characters

    * * *

    @@ -159,7 +159,7 @@ * to check for dangerous characters. * *

    - *

    Nice Properties

    + *

    Nice Properties

    * *

    * If a bytecode name does not contain any escape sequence, @@ -222,7 +222,7 @@ * * * - *

    Suggestions for Human Readable Presentations

    + *

    Suggestions for Human Readable Presentations

    * * *

    diff -r 221a589c52ee -r 4649818834e0 src/jdk.scripting.nashorn/share/classes/module-info.java --- a/src/jdk.scripting.nashorn/share/classes/module-info.java Fri Apr 19 07:55:28 2019 -0400 +++ b/src/jdk.scripting.nashorn/share/classes/module-info.java Fri Apr 19 08:00:42 2019 -0400 @@ -30,7 +30,7 @@ * Nashorn is a runtime environment for programs written in ECMAScript 5.1. *

    * - *

    Usage

    + *

    Usage

    * * The recommended way to use Nashorn is through the * JSR-223 @@ -45,7 +45,7 @@ * * and then use it just as you would any other JSR-223 script engine. See * {@link jdk.nashorn.api.scripting} package for details. - *

    Compatibility

    + *

    Compatibility

    * Nashorn is 100% compliant with the *
    ECMA-262 Standard, Edition 5.1. @@ -55,7 +55,7 @@ * specification (often referred to as "invokedynamic"), as well as * the already mentioned JSR-223. * - *

    Interoperability with the Java platform

    + *

    Interoperability with the Java platform

    * * In addition to being a 100% ECMAScript 5.1 runtime, Nashorn provides features * for interoperability of the ECMAScript programs with the Java platform. @@ -68,7 +68,7 @@ * their properties. In most cases, though, you can't add arbitrary properties * to them, nor can you remove existing properties. * - *

    Java collection handling

    + *

    Java collection handling

    * * Native Java arrays and {@link java.util.List}s support indexed access to * their elements through the property accessors, and {@link java.util.Map}s @@ -79,7 +79,7 @@ * operator gives precedence to map elements. Native Java arrays expose * the {@code length} property. * - *

    ECMAScript primitive types

    + *

    ECMAScript primitive types

    * * ECMAScript primitive types for number, string, and boolean are represented * with {@link java.lang.Number}, {@link java.lang.CharSequence}, and @@ -89,7 +89,7 @@ * cause other subclasses of {@code Number} and internal implementations of * {@code CharSequence} to be used. * - *

    Type conversions

    + *

    Type conversions

    * * When a method on a Java object is invoked, the arguments are converted to * the formal parameter types of the Java method using all allowed ECMAScript @@ -106,7 +106,7 @@ * {@code java.lang.Double}), then Nashorn will of course ensure * the required type is passed. * - *

    SAM types

    + *

    SAM types

    * * As a special extension when invoking Java methods, ECMAScript function * objects can be passed in place of an argument whose Java type is so-called @@ -122,14 +122,14 @@ * the same name. This is done to be consistent with the fact that * ECMAScript does not have the concept of overloaded methods. * - *

    The {@code Java} object

    + *

    The {@code Java} object

    * * Nashorn exposes a non-standard global object named {@code Java} that is * the primary API entry point into Java platform-specific functionality. * You can use it to create instances of Java classes, convert from Java arrays * to native arrays and back, and so on. * - *

    Other non-standard built-in objects

    + *

    Other non-standard built-in objects

    * * In addition to {@code Java}, Nashorn also exposes some other * non-standard built-in objects: diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/ProblemList-graal.txt --- a/test/hotspot/jtreg/ProblemList-graal.txt Fri Apr 19 07:55:28 2019 -0400 +++ b/test/hotspot/jtreg/ProblemList-graal.txt Fri Apr 19 08:00:42 2019 -0400 @@ -218,6 +218,9 @@ compiler/jsr292/InvokerSignatureMismatch.java 8221577 generic-all +compiler/arguments/TestScavengeRootsInCode.java 8207267 generic-all +compiler/loopopts/TestOverunrolling.java 8207267 generic-all + # Graal unit tests org.graalvm.compiler.core.test.CheckGraalInvariants 8205081 org.graalvm.compiler.core.test.OptionsVerifierTest 8205081 diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/containers/docker/JfrNetwork.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/containers/docker/JfrNetwork.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.file.Paths; +import java.util.List; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.process.OutputAnalyzer; + + +// This class is intended to run inside a container +public class JfrNetwork { + // use a unique hostname for container + public static final String HOST_NAME = "container-unique-8221711"; + public static final String JFR_REPORTED_CONTAINER_HOSTNAME_TAG = "jfr_reported_container_hostname="; + + public static void main(String[] args) throws Exception { + String event = args[0]; + try (ServerSocket ss = new ServerSocket()) { + testNetworkInfo(ss, event); + } + } + + private static void assertTrue(boolean expr, String msg) { + if (!expr) { + throw new RuntimeException(msg); + } + } + + private static void testNetworkInfo(ServerSocket ss, String event) throws Exception { + ServerSocketListener server = new ServerSocketListener(ss); + server.start(); + SocketWriter writer = new SocketWriter(ss.getLocalSocketAddress()); + + // setup and start the recording + String recordingPath = event + ".jfr"; + log("========= Recording event: " + event); + Recording r = new Recording(); + r.enable(event); + r.setDestination(Paths.get("/", "tmp", recordingPath)); + r.start(); + + // start the socker writer thread, write some data into the socket + writer.start(); + + // wait for writer thread to terminate, then for server thread, then stop recording + writer.joinAndThrow(); + server.joinAndThrow(); + r.stop(); + + // analyze the recording + List events = RecordingFile.readAllEvents(r.getDestination()); + events.forEach(e -> log ("event = " + e)); + assertTrue(!events.isEmpty(), "No recorded network events"); + RecordedEvent e = events.get(0); + log(JFR_REPORTED_CONTAINER_HOSTNAME_TAG + e.getString("host")); + verifyIpAddress(e.getString("address")); + } + + private static void verifyIpAddress(String eventIp) throws Exception { + ProcessBuilder pb = new ProcessBuilder("hostname", "--ip-address"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + log("hostname --ip-address returned: " + out.getOutput()); + out.shouldContain(eventIp); + } + + private static void log(String msg) { + System.out.println(msg); + } + + + private static class ServerSocketListener extends Thread { + Exception exception; + ServerSocket ss; + + ServerSocketListener(ServerSocket socket) throws Exception { + ss = socket; + ss.setReuseAddress(true); + ss.bind(null); + log("ServerSocker Local Address: " + ss.getLocalSocketAddress()); + } + + public void joinAndThrow() throws Exception { + join(); + if (exception != null) { + throw exception; + } + } + + public void run() { + try { + try (Socket s = ss.accept(); InputStream is = s.getInputStream()) { + System.out.println("ServerSocketListener: accepted socket connection: s = " + s); + is.read(); + is.read(); + is.read(); + } + } catch (Exception e) { + exception = e; + } + } + } + + + private static class SocketWriter extends Thread { + Exception exception; + private SocketAddress ssAddr; + + public SocketWriter(SocketAddress sa) { + this.ssAddr = sa; + System.out.println("SocketWriter(): sa = " + sa); + } + + public void joinAndThrow() throws Exception { + join(); + if (exception != null) { + throw exception; + } + } + + public void run() { + try (Socket s = new Socket()) { + s.connect(ssAddr); + try (OutputStream os = s.getOutputStream()) { + os.write('A'); + os.write('B'); + os.write('C'); + } + } catch (Exception e) { + exception = e; + } + } + } + +} diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/containers/docker/JfrReporter.java --- a/test/hotspot/jtreg/containers/docker/JfrReporter.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/hotspot/jtreg/containers/docker/JfrReporter.java Fri Apr 19 08:00:42 2019 -0400 @@ -22,53 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +import java.nio.file.Path; import java.nio.file.Paths; import jdk.jfr.Recording; +import jdk.jfr.ValueDescriptor; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; - // This class is intended to run inside a container public class JfrReporter { - public static final String TEST_REPORTED_CORES="TEST_REPORTED_CORES"; - public static final String TEST_REPORTED_MEMORY="TEST_REPORTED_MEMORY"; - public static final String TEST_REPORTED_PID="TEST_REPORTED_PID"; - public static final String TESTCASE_CPU="cpu"; - public static final String TESTCASE_MEMORY="memory"; - public static final String TESTCASE_PROCESS="process"; - public static void main(String[] args) throws Exception { - String testCase = args[0]; - System.out.println("Testcase: " + testCase); - switch (testCase) { - case TESTCASE_CPU: - RecordedEvent event = testEvent("jdk.CPUInformation", "cpu.jfr"); - System.out.println(TEST_REPORTED_CORES + "=" + event.getInt("cores")); - break; - case TESTCASE_MEMORY: - event = testEvent("jdk.PhysicalMemory", "memory.jfr"); - System.out.println(TEST_REPORTED_MEMORY + "=" + event.getLong("totalSize")); - break; - case TESTCASE_PROCESS: - event = testEvent("jdk.SystemProcess", "process.jfr"); - System.out.println(TEST_REPORTED_PID + "=" + event.getString("pid")); - break; - default: - throw new IllegalArgumentException("Invalid test case"); + String eventName = args[0]; + try(Recording r = new Recording()) { + r.enable(eventName); + r.start(); + r.stop(); + Path p = Paths.get("/", "tmp", eventName + ".jfr"); + r.dump(p); + for (RecordedEvent e : RecordingFile.readAllEvents(p)) { + System.out.println("===== EventType: " + e.getEventType().getName()); + for (ValueDescriptor v : e.getEventType().getFields()) { + System.out.println(v.getName() + " = " + e.getValue(v.getName())); + } + } } } - - private static RecordedEvent testEvent(String event, String recordingPath) throws Exception { - System.out.println("========= Testing event: " + event); - Recording r = new Recording(); - r.enable(event); - r.setDestination(Paths.get("tmp", recordingPath)); - r.start(); - r.stop(); - - RecordedEvent recordedEvent = RecordingFile.readAllEvents(r.getDestination()).get(0); - System.out.println("RecordedEvent: " + recordedEvent); - return recordedEvent; - } } + \ No newline at end of file diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/containers/docker/TestJFREvents.java --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java Fri Apr 19 08:00:42 2019 -0400 @@ -39,6 +39,8 @@ import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Utils; @@ -68,6 +70,7 @@ testProcessInfo(); + testEnvironmentVariables(); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -79,14 +82,12 @@ DockerTestUtils.dockerRunJava( commonDockerOpts() .addDockerOpts("--cpus=" + valueToSet) - .addClassOptions(JfrReporter.TESTCASE_CPU)) - .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_CORES); - + .addClassOptions("jdk.CPUInformation")) + .shouldHaveExitValue(0); // The following assertion is currently disabled due to JFR reporting incorrect values. // JFR reports values for the host system as opposed to values for the container. // @ignore 8219999 - // .shouldContain(JfrReporter.TEST_REPORTED_CORES + "=" + expectedValue); + // .shouldContain("cores = " + expectedValue"); } @@ -95,9 +96,9 @@ DockerTestUtils.dockerRunJava( commonDockerOpts() .addDockerOpts("--memory=" + valueToSet) - .addClassOptions(JfrReporter.TESTCASE_MEMORY)) + .addClassOptions("jdk.PhysicalMemory")) .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_MEMORY + "=" + expectedValue); + .shouldContain("totalSize = " + expectedValue); } @@ -105,10 +106,9 @@ Common.logNewTestCase("ProcessInfo"); DockerTestUtils.dockerRunJava( commonDockerOpts() - .addClassOptions(JfrReporter.TESTCASE_PROCESS)) + .addClassOptions("jdk.SystemProcess")) .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_PID + "=1"); - + .shouldContain("pid = 1"); } @@ -117,4 +117,28 @@ .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") .addJavaOpts("-cp", "/test-classes/"); } + + + // JTReg always defines the environment variable JAVA_MAIN_CLASS_. + // This variable fits well for use in this test, since it is rather unique. + private static String getTestEnvironmentVariable() throws Exception { + for (String key : System.getenv().keySet()) { + if (key.startsWith("JAVA_MAIN_CLASS")) { + return key; + } + } + throw new RuntimeException("JAVA_MAIN_CLASS_* is not defined"); + } + + + private static void testEnvironmentVariables() throws Exception { + Common.logNewTestCase("EnvironmentVariables"); + + DockerTestUtils.dockerRunJava( + commonDockerOpts() + .addClassOptions("jdk.InitialEnvironmentVariable")) + .shouldHaveExitValue(0) + .shouldContain("key = JAVA_HOME") + .shouldNotContain(getTestEnvironmentVariable()); + } } diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @summary Test JFR network related events inside a container; make sure + * the reported host ip and host name are correctly reported within + * the container. + * @requires docker.support + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * @build JfrNetwork + * @run driver TestJFRNetworkEvents + */ +import jdk.test.lib.containers.docker.Common; +import jdk.test.lib.containers.docker.DockerRunOptions; +import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.Utils; + + +public class TestJFRNetworkEvents { + private static final String imageName = Common.imageName("jfr-network"); + private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); + + public static void main(String[] args) throws Exception { + System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); + if (!DockerTestUtils.canTestDocker()) { + return; + } + + DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker"); + + try { + runTest("jdk.SocketWrite"); + } finally { + DockerTestUtils.removeDockerImage(imageName); + } + } + + private static void runTest(String event) throws Exception { + DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "JfrNetwork") + .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + .addJavaOpts("-cp", "/test-classes/") + .addDockerOpts("--hostname", JfrNetwork.HOST_NAME) + .addClassOptions(event); + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain(JfrNetwork.JFR_REPORTED_CONTAINER_HOSTNAME_TAG + JfrNetwork.HOST_NAME); + } +} diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/runtime/ErrorHandling/ExplicitArithmeticCheck.java --- a/test/hotspot/jtreg/runtime/ErrorHandling/ExplicitArithmeticCheck.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4221448 - * @summary Use explicit check for integer arithmetic exception on win32. - */ - -public class ExplicitArithmeticCheck { - public static void main(String argv[]) throws Exception { - for (int i = 0; i < 64; i++) { - boolean result = false; - int n; - try { - n = 0 / 0; - } catch (ArithmeticException e) { - result = true; - } - if (result == false) { - throw new Error("Failed to throw correct exception!"); - } - result = false; - try { - n = 0 % 0; - } catch (ArithmeticException e) { - result = true; - } - if (result == false) { - throw new Error("Failed to throw correct exception!"); - } - try { - n = 0x80000000 / -1; - } catch (Throwable t) { - throw new Error("Failed to throw correct exception!"); - } - if (n != 0x80000000) { - throw new Error("Incorrect integer arithmetic ! "); - } - try { - n = 0x80000000 % -1; - } catch (Throwable t) { - throw new Error("Failed to throw correct exception!"); - } - if (n != 0) { - throw new Error("Incorrect integer arithmetic!"); - } - } - } -} diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java --- a/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java Fri Apr 19 08:00:42 2019 -0400 @@ -33,10 +33,15 @@ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. MemberNameLeak */ +import java.io.*; +import java.nio.file.*; import java.lang.invoke.*; import java.lang.reflect.*; +import java.text.*; +import java.util.*; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; import sun.hotspot.WhiteBox; import sun.hotspot.code.Compiler; import sun.hotspot.gc.GC; @@ -47,6 +52,7 @@ // The size of the ResolvedMethodTable is 1024. 2000 entries // is enough to trigger a grow/cleaning of the table after a GC. private static int methodCount = 2000; + public static ArrayList keepAlive; static class Leak { public void callMe() { @@ -56,6 +62,8 @@ Leak leak = new Leak(); WhiteBox wb = WhiteBox.getWhiteBox(); + keepAlive = new ArrayList<>(methodCount); + ClassWithManyMethodsClassLoader classLoader = new ClassWithManyMethodsClassLoader(); Class clazz = classLoader.create(className, methodPrefix, methodCount); @@ -74,14 +82,20 @@ MethodHandle mh1 = lookup.findSpecial(clazz, methodName, mt, clazz); mh1.invoke(o); + + keepAlive.add(mh1); } long after = wb.resolvedMethodItemsCount(); + System.out.println("wb.resolvedMethodItemsCount() after setup: " + after); + if (after == before) { throw new RuntimeException("Too few resolved methods"); } + keepAlive = null; + // Wait until ServiceThread cleans ResolvedMethod table int cnt = 0; while (true) { @@ -99,27 +113,48 @@ } } + private static Path createGcLogPath(String prefix) throws IOException { + Path gcLog = Utils.createTempFile(prefix, "log"); + Files.delete(gcLog); + return gcLog; + } + + private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + public static void test(GC gc, boolean doConcurrent) throws Throwable { - System.err.println("test(" + gc + ", " + doConcurrent + ")"); + Path gcLogPath = createGcLogPath("gc." + gc + "." + doConcurrent); + System.err.println("test(" + gc + ", " + doConcurrent + ")" + " " + dateFormat.format(new Date())); // Run this Leak class with logging ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-Xlog:membername+table=trace", + "-Xlog:membername+table=trace,gc+verify=debug,gc:" + gcLogPath + ":time,utctime,uptime,pid,level,tags", "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-Xbootclasspath/a:.", + "-XX:+VerifyBeforeGC", + "-XX:+VerifyAfterGC", doConcurrent ? "-XX:+ExplicitGCInvokesConcurrent" : "-XX:-ExplicitGCInvokesConcurrent", "-XX:+ClassUnloading", "-XX:+ClassUnloadingWithConcurrentMark", "-XX:+Use" + gc + "GC", Leak.class.getName()); + + // Check process OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.outputTo(System.out); + output.errorTo(System.err); + output.shouldHaveExitValue(0); + + // Check gc log file + OutputAnalyzer gcLogOutput = new OutputAnalyzer(gcLogPath); + // Hardcoded names for classes generated by GeneratedClassLoader String descriptor = className + "." + methodPrefix + "0()V"; - output.shouldContain("ResolvedMethod entry added for " + descriptor); - output.shouldContain("ResolvedMethod entry found for " + descriptor); - output.shouldContain("ResolvedMethod entry removed"); - output.shouldHaveExitValue(0); + gcLogOutput.shouldContain("ResolvedMethod entry added for " + descriptor); + gcLogOutput.shouldContain("ResolvedMethod entry found for " + descriptor); + gcLogOutput.shouldContain("ResolvedMethod entry removed"); + + System.err.println("test(" + gc + ", " + doConcurrent + ")" + " done " + dateFormat.format(new Date())); } private static boolean supportsSTW(GC gc) { diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/runtime/Thread/MonitorCacheMaybeExpand_DeadLock.java --- a/test/hotspot/jtreg/runtime/Thread/MonitorCacheMaybeExpand_DeadLock.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4087516 - * @summary Incorrect locking leads to deadlock in monitorCacheMaybeExpand. - * @author Anand Palaniswamy - * @build MonitorCacheMaybeExpand_DeadLock - * @run main/othervm MonitorCacheMaybeExpand_DeadLock - */ - -/** - * Background on the bug: - * - * The thread local monitor cache had a locking bug (till - * 1.2beta1) where two threads trying to expand the monitor cache - * at the same time would cause deadlock. The code paths that the - * two threads must be executing for this to happen is described - * in the bug report. - * - * Caveat and red-flag: - * - * Since deadlocks are very timing dependent, there is a good - * chance this test case will not catch the bug most of the time - * -- on your machine and setting, it is _possible_ that the two - * threads might not try a monitorCacheExpand at the same - * time. But in practice, on Solaris native threads, this program - * deadlocks the VM in about 2 seconds pretty consistently, - * whether MP or not. - * - * The rationale for running this test despite this rather large - * caveat is that at worst, it can do no harm. - * - * The idea: - * - * Is to create two monitor hungry threads. - * - * Originally Tom Rodriguez and I suspected that this weird state - * of two threads trying to expand monitor cache can happen only - * if: - * - * Thread 1: Is in the middle of a monitorCacheMaybeExpand. - * Thread 2: Runs GC and tries to freeClasses(). This causes - * sysFree() to be invoked, which in turn needs a - * mutex_lock -- and oops, we end up deadlocking - * with 1 on green_threads. - * - * Which is why this test tries to cause class GC at regular - * intervals. - * - * Turns out that the GC is not required. Two instances of the - * monitor hungry threads deadlock the VM pretty quick. :-) Infact - * the static initializer in the forName'd classes running - * alongside one of the hungry threads is sufficient to - * deadlock. Still keep the GC stuff just-in-case (and also - * because I wrote it :-). - * - */ -public class MonitorCacheMaybeExpand_DeadLock { - - /** - * A monitor-hungry thread. - */ - static class LotsaMonitors extends Thread { - - /** How many recursions? Could cause Java stack overflow. */ - static final int MAX_DEPTH = 800; - - /** What is our depth? */ - int depth = 0; - - /** Thread ID */ - int tid; - - /** So output will have thread number. */ - public LotsaMonitors(int tid, int depth) { - super("LotsaMonitors #" + new Integer(tid).toString()); - this.tid = tid; - this.depth = depth; - } - - /** Start a recursion that grabs monitors. */ - public void run() { - System.out.println(">>>Starting " + this.toString() + " ..."); - Thread.currentThread().yield(); - this.recurse(); - System.out.println("<< 0) { - new LotsaMonitors(tid, depth-1).recurse(); - } - } - } - - /** - * The test. - */ - public static void main(String[] args) { - /* Start the two of these crazy threads. */ - new LotsaMonitors(1, LotsaMonitors.MAX_DEPTH).start(); - new LotsaMonitors(2, LotsaMonitors.MAX_DEPTH).start(); - - /* And sit there and GC for good measure. */ - for (int i = 0; i < MAX_GC_ITERATIONS; i++) { - new LotsaMonitors(i+3, LotsaMonitors.MAX_DEPTH).start(); - System.out.println(">>>Loading 10 classes and gc'ing ..."); - Class[] classes = new Class[10]; - fillClasses(classes); - classes = null; - System.gc(); - Thread.currentThread().yield(); - System.out.println("<<", "()V", null, null); diff -r 221a589c52ee -r 4649818834e0 test/hotspot/jtreg/runtime/interpreter/WideStrictInline.java --- a/test/hotspot/jtreg/runtime/interpreter/WideStrictInline.java Fri Apr 19 07:55:28 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4169183 - * @summary Check for correct inlining by the interpreter (widefp and strictfp). - * The default is widefp. A strictfp method was getting inlined - * into a widefp method. - */ - -import java.io.PrintStream; - -public class WideStrictInline { - static PrintStream out; - static float halfUlp; - - static { - halfUlp = 1; - for ( int i = 127 - 24; i > 0; i-- ) - halfUlp *= 2; - } - - public static void main(String argv[]) throws Exception { - out = System.err; - pr(-1,"halfUlp",halfUlp); - WideStrictInline obj = new WideStrictInline(); - for( int i=0; i<48; i++ ) - obj.instanceMethod( i ); - } - - private static void pr(int i, String desc, float r) { - out.print(" i=("+i+") "+desc+" ; == "+r); - out.println(" , 0x"+Integer.toHexString(Float.floatToIntBits(r))); - } - - private static strictfp float WideStrictInline(float par) { - return par; - } - - public static strictfp float strictValue(int i) { - float r; - switch (i%4) { - case 0: r = -Float.MAX_VALUE; break; - case 1: r = Float.MAX_VALUE; break; - case 2: r = Float.MIN_VALUE; break; - default : r = 1L << 24; - } - return r; - } - - void instanceMethod (int i) throws Exception { - float r; - switch (i%4) { - case 0: - if (!Float.isInfinite( WideStrictInline(strictValue(i)*2) + - Float.MAX_VALUE )) - { - pr(i, - "WideStrictInline(-Float.MAX_VALUE * 2) " + - "!= Float.NEGATIVE_INFINITY" - ,WideStrictInline(strictValue(i)*2) + Float.MAX_VALUE); - } - r = WideStrictInline(strictValue(i)*2) + Float.MAX_VALUE; - if ( !Float.isInfinite( r ) ) { - pr(i,"r != Float.NEGATIVE_INFINITY",r); - throw new RuntimeException(); - } - break; - case 1: - if (!Float.isInfinite(WideStrictInline(strictValue(i)+halfUlp) - - Float.MAX_VALUE )) { - pr(i,"WideStrictInline(Float.MAX_VALUE+halfUlp) " + - "!= Float.POSITIVE_INFINITY" - ,WideStrictInline(strictValue(i)+halfUlp) - Float.MAX_VALUE); - } - r = WideStrictInline(strictValue(i)+halfUlp) - Float.MAX_VALUE; - if ( !Float.isInfinite( r ) ) { - pr(i,"r != Float.POSITIVE_INFINITY",r); - throw new RuntimeException(); - } - break; - case 2: - if (WideStrictInline(strictValue(i)/2) != 0) { - pr(i,"WideStrictInline(Float.MIN_VALUE/2) != 0", - WideStrictInline(strictValue(i)/2)); - } - r = WideStrictInline(strictValue(i)/2); - if ( r != 0 ) { - pr(i,"r != 0",r); - throw new RuntimeException(); - } - break; - default: - if (WideStrictInline(strictValue(i)-0.5f) - strictValue(i) != 0) { - pr(i,"WideStrictInline(2^24-0.5) != 2^24", - WideStrictInline(strictValue(i)-0.5f)); - } - r = WideStrictInline(strictValue(i)-0.5f); - if ( r - strictValue(i) != 0 ) { - pr(i,"r != 2^24",r); - throw new RuntimeException(); - } - } - } - -} diff -r 221a589c52ee -r 4649818834e0 test/jaxp/javax/xml/jaxp/unittest/parsers/BaseParsingTest.java --- a/test/jaxp/javax/xml/jaxp/unittest/parsers/BaseParsingTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jaxp/javax/xml/jaxp/unittest/parsers/BaseParsingTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,19 +22,22 @@ */ package parsers; +import java.io.ByteArrayInputStream; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; +import static org.testng.Assert.assertEquals; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; +import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * @test - * @bug 8169450 + * @bug 8169450 8222415 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true parsers.BaseParsingTest * @run testng/othervm parsers.BaseParsingTest @@ -143,7 +146,7 @@ * @bug 8169450 * This particular issue does not appear in DOM parsing since the spaces are * normalized during version detection. This test case then serves as a guard - * against such an issue from occuring in the version detection. + * against such an issue from occurring in the version detection. * * @param xml the test xml * @throws Exception if the parser fails to parse the xml @@ -151,8 +154,24 @@ @Test(dataProvider = "xmlDeclarations") public void testWithDOM(String xml) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setValidating(true); DocumentBuilder db = dbf.newDocumentBuilder(); db.parse(new InputSource(new StringReader(xml))); } + + /** + * @bug 8222415 + * Verifies that the parser is configured properly for UTF-16BE or LE. + * @throws Exception + */ + @Test + public void testEncoding() throws Exception { + ByteArrayInputStream bis = new ByteArrayInputStream( + " ".getBytes("UnicodeLittle")); + InputSource is = new InputSource(bis); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + + Document doc = db.parse(is); + assertEquals("UTF-16LE", doc.getInputEncoding()); + } } diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/math/BigDecimal/IntValueExactTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/math/BigDecimal/IntValueExactTests.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8211936 + * @summary Tests of BigDecimal.intValueExact + */ +import java.math.*; +import java.util.List; +import java.util.Map; +import static java.util.Map.entry; + +public class IntValueExactTests { + public static void main(String... args) { + int failures = 0; + + failures += intValueExactSuccessful(); + failures += intValueExactExceptional(); + + if (failures > 0) { + throw new RuntimeException("Incurred " + failures + + " failures while testing intValueExact."); + } + } + + private static int simpleIntValueExact(BigDecimal bd) { + return bd.toBigIntegerExact().intValue(); + } + + private static int intValueExactSuccessful() { + int failures = 0; + + // Strings used to create BigDecimal instances on which invoking + // intValueExact() will succeed. + Map successCases = + Map.ofEntries(entry(new BigDecimal("2147483647"), Integer.MAX_VALUE), // 2^31 -1 + entry(new BigDecimal("2147483647.0"), Integer.MAX_VALUE), + entry(new BigDecimal("2147483647.00"), Integer.MAX_VALUE), + + entry(new BigDecimal("-2147483648"), Integer.MIN_VALUE), // -2^31 + entry(new BigDecimal("-2147483648.0"), Integer.MIN_VALUE), + entry(new BigDecimal("-2147483648.00"),Integer.MIN_VALUE), + + entry(new BigDecimal("1e0"), 1), + entry(new BigDecimal(BigInteger.ONE, -9), 1_000_000_000), + + entry(new BigDecimal("0e13"), 0), // Fast path zero + entry(new BigDecimal("0e32"), 0), + entry(new BigDecimal("0e512"), 0), + + entry(new BigDecimal("10.000000000000000000000000000000000"), 10)); + + for (var testCase : successCases.entrySet()) { + BigDecimal bd = testCase.getKey(); + int expected = testCase.getValue(); + try { + int intValueExact = bd.intValueExact(); + if (expected != intValueExact || + intValueExact != simpleIntValueExact(bd)) { + failures++; + System.err.println("Unexpected intValueExact result " + intValueExact + + " on " + bd); + } + } catch (Exception e) { + failures++; + System.err.println("Error on " + bd + "\tException message:" + e.getMessage()); + } + } + return failures; + } + + private static int intValueExactExceptional() { + int failures = 0; + List exceptionalCases = + List.of(new BigDecimal("2147483648"), // Integer.MAX_VALUE + 1 + new BigDecimal("2147483648.0"), + new BigDecimal("2147483648.00"), + new BigDecimal("-2147483649"), // Integer.MIN_VALUE - 1 + new BigDecimal("-2147483649.1"), + new BigDecimal("-2147483649.01"), + + new BigDecimal("9999999999999999999999999999999"), + new BigDecimal("10000000000000000000000000000000"), + + new BigDecimal("0.99"), + new BigDecimal("0.999999999999999999999")); + + for (BigDecimal bd : exceptionalCases) { + try { + int intValueExact = bd.intValueExact(); + failures++; + System.err.println("Unexpected non-exceptional intValueExact on " + bd); + } catch (ArithmeticException e) { + // Success; + } + } + return failures; + } +} diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/math/BigDecimal/IntegralValueTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/math/BigDecimal/IntegralValueTests.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8211936 + * @summary Tests of BigDecimal.intValue() and BigDecimal.longValue() + */ +import java.math.BigDecimal; +import java.util.Map; + +public class IntegralValueTests { + public static void main(String... args) { + int failures = + integralValuesTest(INT_VALUES, true) + + integralValuesTest(LONG_VALUES, false); + if (failures != 0) { + throw new RuntimeException + ("Incurred " + failures + " failures for {int,long}Value()."); + } + } + + private static final Map INT_VALUES = + Map.ofEntries( + + // 2**31 - 1 + Map.entry(new BigDecimal("2147483647"), Integer.MAX_VALUE), + Map.entry(new BigDecimal("2147483647.0"), Integer.MAX_VALUE), + Map.entry(new BigDecimal("2147483647.00"), Integer.MAX_VALUE), + + Map.entry(new BigDecimal("-2147483647"), -Integer.MAX_VALUE), + Map.entry(new BigDecimal("-2147483647.0"), -Integer.MAX_VALUE), + + // -2**31 + Map.entry(new BigDecimal("-2147483648"), Integer.MIN_VALUE), + Map.entry(new BigDecimal("-2147483648.1"), Integer.MIN_VALUE), + Map.entry(new BigDecimal("-2147483648.01"), Integer.MIN_VALUE), + + // -2**31 + 1 truncation to 2**31 - 1 + Map.entry(new BigDecimal("-2147483649"), Integer.MAX_VALUE), + + // 2**64 - 1 truncation to 1 + Map.entry(new BigDecimal("4294967295"), -1), + + // 2**64 truncation to 0 + Map.entry(new BigDecimal("4294967296"), 0), + + // Fast path truncation to 0 + Map.entry(new BigDecimal("1e32"), 0), + + // Slow path truncation to -2**31 + Map.entry(new BigDecimal("1e31"), Integer.MIN_VALUE), + + // Slow path + Map.entry(new BigDecimal("1e0"), 1), + + // Fast path round to 0 + Map.entry(new BigDecimal("9e-1"), 0), + + // Some random values + Map.entry(new BigDecimal("900e-1"), 90), // Increasing negative exponents + Map.entry(new BigDecimal("900e-2"), 9), + Map.entry(new BigDecimal("900e-3"), 0), + + // Fast path round to 0 + Map.entry(new BigDecimal("123456789e-9"), 0), + + // Slow path round to 1 + Map.entry(new BigDecimal("123456789e-8"), 1), + + // Increasing positive exponents + Map.entry(new BigDecimal("10000001e1"), 100000010), + Map.entry(new BigDecimal("10000001e10"), -1315576832), + Map.entry(new BigDecimal("10000001e100"), 0), + Map.entry(new BigDecimal("10000001e1000"), 0), + Map.entry(new BigDecimal("10000001e10000"), 0), + Map.entry(new BigDecimal("10000001e100000"), 0), + Map.entry(new BigDecimal("10000001e1000000"), 0), + Map.entry(new BigDecimal("10000001e10000000"), 0), + Map.entry(new BigDecimal("10000001e100000000"), 0), + Map.entry(new BigDecimal("10000001e1000000000"), 0), + + // Increasing negative exponents + Map.entry(new BigDecimal("10000001e-1"), 1000000), + Map.entry(new BigDecimal("10000001e-10"), 0), + Map.entry(new BigDecimal("10000001e-100"), 0), + Map.entry(new BigDecimal("10000001e-1000"), 0), + Map.entry(new BigDecimal("10000001e-10000"), 0), + Map.entry(new BigDecimal("10000001e-100000"), 0), + Map.entry(new BigDecimal("10000001e-1000000"), 0), + Map.entry(new BigDecimal("10000001e-10000000"), 0), + Map.entry(new BigDecimal("10000001e-100000000"), 0), + Map.entry(new BigDecimal("10000001e-1000000000"), 0), + + // Currency calculation to 4 places + Map.entry(new BigDecimal("12345.0001"), 12345), + Map.entry(new BigDecimal("12345.9999"), 12345), + Map.entry(new BigDecimal("-12345.0001"), -12345), + Map.entry(new BigDecimal("-12345.9999"), -12345)); + + private static final Map LONG_VALUES = + Map.ofEntries( + // 2**63 - 1 + Map.entry(new BigDecimal("9223372036854775807"), Long.MAX_VALUE), + Map.entry(new BigDecimal("9223372036854775807.0"), Long.MAX_VALUE), + Map.entry(new BigDecimal("9223372036854775807.00"), Long.MAX_VALUE), + + // 2**63 truncation to -2**63 + Map.entry(new BigDecimal("-9223372036854775808"), Long.MIN_VALUE), + Map.entry(new BigDecimal("-9223372036854775808.1"), Long.MIN_VALUE), + Map.entry(new BigDecimal("-9223372036854775808.01"), Long.MIN_VALUE), + + // -2**63 + 1 truncation to 2**63 - 1 + Map.entry(new BigDecimal("-9223372036854775809"), 9223372036854775807L), + + // 2**64 - 1 truncation to -1 + Map.entry(new BigDecimal("18446744073709551615"), -1L), + + // 2**64 truncation to 0 + Map.entry(new BigDecimal("18446744073709551616"), 0L), + + // Slow path truncation to -2**63 + Map.entry(new BigDecimal("1e63"), -9223372036854775808L), + Map.entry(new BigDecimal("-1e63"), -9223372036854775808L), + // Fast path with larger magnitude scale + Map.entry(new BigDecimal("1e64"), 0L), + Map.entry(new BigDecimal("-1e64"), 0L), + Map.entry(new BigDecimal("1e65"), 0L), + Map.entry(new BigDecimal("-1e65"), 0L), + + // Slow path + Map.entry(new BigDecimal("1e0"), 1L), + + // Fast path round to 0 + Map.entry(new BigDecimal("9e-1"), 0L), + + // Some random values + Map.entry(new BigDecimal("900e-1"), 90L), // Increasing negative exponents + Map.entry(new BigDecimal("900e-2"), 9L), + Map.entry(new BigDecimal("900e-3"), 0L), + + // Fast path round to 0 + Map.entry(new BigDecimal("123456789e-9"), 0L), + + // Slow path round to 1 + Map.entry(new BigDecimal("123456789e-8"), 1L), + + // Increasing positive exponents + Map.entry(new BigDecimal("10000001e1"), 100000010L), + Map.entry(new BigDecimal("10000001e10"), 100000010000000000L), + Map.entry(new BigDecimal("10000001e100"), 0L), + Map.entry(new BigDecimal("10000001e1000"), 0L), + Map.entry(new BigDecimal("10000001e10000"), 0L), + Map.entry(new BigDecimal("10000001e100000"), 0L), + Map.entry(new BigDecimal("10000001e1000000"), 0L), + Map.entry(new BigDecimal("10000001e10000000"), 0L), + Map.entry(new BigDecimal("10000001e100000000"), 0L), + Map.entry(new BigDecimal("10000001e1000000000"), 0L), + + // Increasing negative exponents + Map.entry(new BigDecimal("10000001e-1"), 1000000L), + Map.entry(new BigDecimal("10000001e-10"), 0L), + Map.entry(new BigDecimal("10000001e-100"), 0L), + Map.entry(new BigDecimal("10000001e-1000"), 0L), + Map.entry(new BigDecimal("10000001e-10000"), 0L), + Map.entry(new BigDecimal("10000001e-100000"), 0L), + Map.entry(new BigDecimal("10000001e-1000000"), 0L), + Map.entry(new BigDecimal("10000001e-10000000"), 0L), + Map.entry(new BigDecimal("10000001e-100000000"), 0L), + Map.entry(new BigDecimal("10000001e-1000000000"), 0L), + + // Currency calculation to 4 places + Map.entry(new BigDecimal("12345.0001"), 12345L), + Map.entry(new BigDecimal("12345.9999"), 12345L), + Map.entry(new BigDecimal("-12345.0001"), -12345L), + Map.entry(new BigDecimal("-12345.9999"), -12345L)); + + private static int integralValuesTest(Map v, boolean isInt) { + System.err.format("Testing %s%n", isInt ? "Integer" : "Long"); + int failures = 0; + for (var testCase : v.entrySet()) { + BigDecimal bd = testCase.getKey(); + Number expected = testCase.getValue(); + try { + if (isInt) { + int intValue = bd.intValue(); + if (intValue != (int)expected) { + failures += reportError(bd, expected, intValue, isInt); + } + } else { + long longValue = bd.longValue(); + if (longValue != (long)expected) { + failures += reportError(bd, expected, longValue, isInt); + } + } + } catch (Exception e) { + failures++; + System.err.format("Unexpected exception %s for %s%n", + e, bd.toString()); + } + } + return failures; + } + + private static int reportError(BigDecimal bd, Number expected, long longValue, boolean isInt) { + System.err.format("For %s, scale=%d, expected %d, actual %d, simple %d%n", + bd.toString(), bd.scale(), + (isInt ? (Integer) expected : (Long) expected ), + longValue, + (isInt ? simpleIntValue(bd): simpleLongValue(bd) )); + return 1; + } + + private static long simpleLongValue(BigDecimal bd) { + return bd.toBigInteger().longValue(); + } + + private static int simpleIntValue(BigDecimal bd) { + return bd.toBigInteger().intValue(); + } +} diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/math/BigDecimal/LongValueExactTests.java --- a/test/jdk/java/math/BigDecimal/LongValueExactTests.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/math/BigDecimal/LongValueExactTests.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,65 +23,98 @@ /** * @test - * @bug 6806261 + * @bug 6806261 8211936 * @summary Tests of BigDecimal.longValueExact */ import java.math.*; +import java.util.List; +import java.util.Map; +import static java.util.Map.entry; public class LongValueExactTests { + public static void main(String... args) { + int failures = 0; - private static int longValueExactTests() { + failures += longValueExactSuccessful(); + failures += longValueExactExceptional(); + + if (failures > 0) { + throw new RuntimeException("Incurred " + failures + + " failures while testing longValueExact."); + } + } + + private static long simpleLongValueExact(BigDecimal bd) { + return bd.toBigIntegerExact().longValue(); + } + + private static int longValueExactSuccessful() { int failures = 0; - String[] testStrings = { - "9223372036854775807", - "9223372036854775807.0", - "9223372036854775807.00", - "-9223372036854775808", - "-9223372036854775808.0", - "-9223372036854775808.00", - }; + // Strings used to create BigDecimal instances on which invoking + // longValueExact() will succeed. + Map successCases = + Map.ofEntries(entry(new BigDecimal("9223372036854775807"), Long.MAX_VALUE), // 2^63 -1 + entry(new BigDecimal("9223372036854775807.0"), Long.MAX_VALUE), + entry(new BigDecimal("9223372036854775807.00"), Long.MAX_VALUE), + + entry(new BigDecimal("-9223372036854775808"), Long.MIN_VALUE), // -2^63 + entry(new BigDecimal("-9223372036854775808.0"), Long.MIN_VALUE), + entry(new BigDecimal("-9223372036854775808.00"),Long.MIN_VALUE), + + entry(new BigDecimal("1e0"), 1L), + entry(new BigDecimal(BigInteger.ONE, -18), 1_000_000_000_000_000_000L), - for (String longValue : testStrings) { + entry(new BigDecimal("0e13"), 0L), // Fast path zero + entry(new BigDecimal("0e64"), 0L), + entry(new BigDecimal("0e1024"), 0L), + + entry(new BigDecimal("10.000000000000000000000000000000000"), 10L)); + + for (var testCase : successCases.entrySet()) { + BigDecimal bd = testCase.getKey(); + long expected = testCase.getValue(); try { - BigDecimal bd = new BigDecimal(longValue); long longValueExact = bd.longValueExact(); + if (expected != longValueExact || + longValueExact != simpleLongValueExact(bd)) { + failures++; + System.err.println("Unexpected longValueExact result " + longValueExact + + " on " + bd); + } } catch (Exception e) { failures++; + System.err.println("Error on " + bd + "\tException message:" + e.getMessage()); } } + return failures; + } - // The following Strings are supposed to make longValueExact throw - // ArithmeticException. - String[] testStrings2 = { - "9223372036854775808", - "9223372036854775808.0", - "9223372036854775808.00", - "-9223372036854775809", - "-9223372036854775808.1", - "-9223372036854775808.01", - }; + private static int longValueExactExceptional() { + int failures = 0; + List exceptionalCases = + List.of(new BigDecimal("9223372036854775808"), // Long.MAX_VALUE + 1 + new BigDecimal("9223372036854775808.0"), + new BigDecimal("9223372036854775808.00"), + new BigDecimal("-9223372036854775809"), // Long.MIN_VALUE - 1 + new BigDecimal("-9223372036854775808.1"), + new BigDecimal("-9223372036854775808.01"), - for (String bigValue : testStrings2) { + new BigDecimal("9999999999999999999"), + new BigDecimal("10000000000000000000"), + + new BigDecimal("0.99"), + new BigDecimal("0.999999999999999999999")); + + for (BigDecimal bd : exceptionalCases) { try { - BigDecimal bd = new BigDecimal(bigValue); long longValueExact = bd.longValueExact(); failures++; + System.err.println("Unexpected non-exceptional longValueExact on " + bd); } catch (ArithmeticException e) { // Success; } } return failures; } - - public static void main(String argv[]) { - int failures = 0; - - failures += longValueExactTests(); - - if (failures > 0) { - throw new RuntimeException("Incurred " + failures + - " failures while testing longValueExact."); - } - } } diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/net/httpclient/DigestEchoServer.java --- a/test/jdk/java/net/httpclient/DigestEchoServer.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/net/httpclient/DigestEchoServer.java Fri Apr 19 08:00:42 2019 -0400 @@ -80,6 +80,8 @@ Boolean.parseBoolean(System.getProperty("test.debug", "false")); public static final boolean NO_LINGER = Boolean.parseBoolean(System.getProperty("test.nolinger", "false")); + public static final boolean TUNNEL_REQUIRES_HOST = + Boolean.parseBoolean(System.getProperty("test.requiresHost", "false")); public enum HttpAuthType { SERVER, PROXY, SERVER307, PROXY305 /* add PROXY_AND_SERVER and SERVER_PROXY_NONE */ @@ -1522,6 +1524,36 @@ } } + boolean badRequest(StringBuilder response, String hostport, List hosts) { + String message = null; + if (hosts.isEmpty()) { + message = "No host header provided\r\n"; + } else if (hosts.size() > 1) { + message = "Multiple host headers provided\r\n"; + for (String h : hosts) { + message = message + "host: " + h + "\r\n"; + } + } else { + String h = hosts.get(0); + if (!hostport.equalsIgnoreCase(h) + && !hostport.equalsIgnoreCase(h + ":80") + && !hostport.equalsIgnoreCase(h + ":443")) { + message = "Bad host provided: [" + h + + "] doesnot match [" + hostport + "]\r\n"; + } + } + if (message != null) { + int length = message.getBytes(StandardCharsets.UTF_8).length; + response.append("HTTP/1.1 400 BadRequest\r\n") + .append("Content-Length: " + length) + .append("\r\n\r\n") + .append(message); + return true; + } + + return false; + } + boolean authorize(StringBuilder response, String requestLine, String headers) { if (authorization != null) { return authorization.authorize(response, requestLine, headers); @@ -1635,6 +1667,7 @@ assert connect.equalsIgnoreCase("connect"); String hostport = tokenizer.nextToken(); InetSocketAddress targetAddress; + List hosts = new ArrayList<>(); try { URI uri = new URI("https", hostport, "/", null, null); int port = uri.getPort(); @@ -1659,9 +1692,30 @@ System.out.println(now() + "Tunnel: Reading header: " + (line = readLine(ccis))); headers.append(line).append("\r\n"); + int index = line.indexOf(':'); + if (index >= 0) { + String key = line.substring(0, index).trim(); + if (key.equalsIgnoreCase("host")) { + hosts.add(line.substring(index+1).trim()); + } + } + } + StringBuilder response = new StringBuilder(); + if (TUNNEL_REQUIRES_HOST) { + if (badRequest(response, hostport, hosts)) { + System.out.println(now() + "Tunnel: Sending " + response); + // send the 400 response + pw.print(response.toString()); + pw.flush(); + toClose.close(); + continue; + } else { + assert hosts.size() == 1; + System.out.println(now() + + "Tunnel: Host header verified " + hosts); + } } - StringBuilder response = new StringBuilder(); final boolean authorize = authorize(response, requestLine, headers.toString()); if (!authorize) { System.out.println(now() + "Tunnel: Sending " diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/net/httpclient/HttpsTunnelTest.java --- a/test/jdk/java/net/httpclient/HttpsTunnelTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/net/httpclient/HttpsTunnelTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,9 @@ * proxy P is downgraded to HTTP/1.1, then a new h2 request * going to a different host through the same proxy will not * be preemptively downgraded. That, is the stack should attempt - * a new h2 connection to the new host. - * @bug 8196967 + * a new h2 connection to the new host. It also verifies that + * the stack sends the appropriate "host" header to the proxy. + * @bug 8196967 8222527 * @library /test/lib http2/server * @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters DigestEchoServer HttpsTunnelTest * @modules java.net.http/jdk.internal.net.http.common @@ -58,7 +59,14 @@ * java.base/sun.net.www.http * java.base/sun.net.www * java.base/sun.net - * @run main/othervm -Djdk.internal.httpclient.debug=true HttpsTunnelTest + * @run main/othervm -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true HttpsTunnelTest + * @run main/othervm -Dtest.requiresHost=true + * -Djdk.httpclient.allowRestrictedHeaders=host + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true HttpsTunnelTest + * */ public class HttpsTunnelTest implements HttpServerAdapters { @@ -116,6 +124,18 @@ try { URI uri1 = new URI("https://" + http1Server.serverAuthority() + "/foo/https1"); URI uri2 = new URI("https://" + http2Server.serverAuthority() + "/foo/https2"); + + boolean provideCustomHost = "host".equalsIgnoreCase( + System.getProperty("jdk.httpclient.allowRestrictedHeaders","")); + + String customHttp1Host = null, customHttp2Host = null; + if (provideCustomHost) { + customHttp1Host = makeCustomHostString(http1Server, uri1); + out.println("HTTP/1.1: <" + uri1 + "> [custom host: " + customHttp1Host + "]"); + customHttp2Host = makeCustomHostString(http2Server, uri2); + out.println("HTTP/2: <" + uri2 + "> [custom host: " + customHttp2Host + "]"); + } + ProxySelector ps = ProxySelector.of(proxy.getProxyAddress()); //HttpClient.Builder.NO_PROXY; HttpsTunnelTest test = new HttpsTunnelTest(); @@ -126,11 +146,12 @@ assert lines.size() == data.length; String body = lines.stream().collect(Collectors.joining("\r\n")); HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublishers.ofString(body); - HttpRequest req1 = HttpRequest + HttpRequest.Builder req1Builder = HttpRequest .newBuilder(uri1) .version(Version.HTTP_2) - .POST(reqBody) - .build(); + .POST(reqBody); + if (provideCustomHost) req1Builder.header("host", customHttp1Host); + HttpRequest req1 = req1Builder.build(); out.println("\nPosting to HTTP/1.1 server at: " + req1); HttpResponse> response = client.send(req1, BodyHandlers.ofLines()); out.println("Checking response..."); @@ -145,12 +166,14 @@ if (!lines.equals(respLines)) { throw new RuntimeException("Unexpected response 1: " + respLines); } + HttpRequest.BodyPublisher reqBody2 = HttpRequest.BodyPublishers.ofString(body); - HttpRequest req2 = HttpRequest + HttpRequest.Builder req2Builder = HttpRequest .newBuilder(uri2) .version(Version.HTTP_2) - .POST(reqBody2) - .build(); + .POST(reqBody2); + if (provideCustomHost) req2Builder.header("host", customHttp2Host); + HttpRequest req2 = req2Builder.build(); out.println("\nPosting to HTTP/2 server at: " + req2); response = client.send(req2, BodyHandlers.ofLines()); out.println("Checking response..."); @@ -176,4 +199,26 @@ } } + /** + * Builds a custom host string that is different to what is in the URI + * authority, that is textually different than what the stack would + * send. For CONNECT we should ignore any custom host settings. + * The tunnelling proxy will fail with badRequest 400 if it receives + * the custom host instead of the expected URI authority string. + * @param server The target server. + * @param uri The URI to the target server + * @return a host value for the custom host header. + */ + static final String makeCustomHostString(HttpTestServer server, URI uri) { + String customHttpHost; + if (server.serverAuthority().contains("localhost")) { + customHttpHost = InetAddress.getLoopbackAddress().getHostAddress(); + } else { + customHttpHost = InetAddress.getLoopbackAddress().getHostName(); + } + if (customHttpHost.contains(":")) customHttpHost = "[" + customHttpHost + "]"; + if (uri.getPort() != -1) customHttpHost = customHttpHost + ":" + uri.getPort(); + return customHttpHost; + } + } diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java --- a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8087112 + * @bug 8087112 8222527 * @summary this test verifies that a client may provides authorization * headers directly when connecting with a server over SSL, and * it verifies that the client honor the jdk.http.auth.*.disabledSchemes @@ -45,10 +45,12 @@ * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes=Basic * -Djdk.http.auth.tunneling.disabledSchemes=Basic + * -Dtest.requiresHost=true * ProxyAuthDisabledSchemesSSL SSL PROXY * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes=Digest * -Djdk.http.auth.tunneling.disabledSchemes=Digest + * -Dtest.requiresHost=true * ProxyAuthDisabledSchemesSSL SSL PROXY */ diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/nio/channels/Channels/Basic.java --- a/test/jdk/java/nio/channels/Channels/Basic.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/nio/channels/Channels/Basic.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4417152 4481572 6248930 6725399 6884800 + * @bug 4417152 4481572 6248930 6725399 6884800 8220477 * @summary Test Channels basic functionality */ @@ -31,7 +31,6 @@ import java.nio.charset.*; import java.nio.channels.*; - public class Basic { static String message; @@ -204,6 +203,8 @@ writeOut(blah, ITERATIONS); testNewReader(blah); + testNewWriterClose(); + testNewReaderClose(); } finally { blah.delete(); } @@ -399,6 +400,98 @@ r.close(); fis.close(); } + + private static void testNewWriterClose() throws Exception { + Writer writer = null; + try { + WritableByteChannel channel = new WritableByteChannel() { + @Override + public int write(ByteBuffer src) throws IOException { + return 0; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() throws IOException { + throw new IOException(); + } + }; + writer = Channels.newWriter(channel, + StandardCharsets.UTF_8.newEncoder(), -1); + writer.close(); + } catch (IOException ioe) { + Exception theException = null; + try { + writer.write(1); + writer.flush(); + } catch (Exception e) { + theException = e; + } finally { + if (theException == null) { + throw new RuntimeException("IOException not thrown"); + } else if (!(theException instanceof IOException)) { + throw new RuntimeException("Exception not an IOException: " + + theException); + } else { + String message = theException.getMessage(); + if (!message.equals("Stream closed")) { + throw new RuntimeException("Unexpected message " + + message); + } + } + } + } + } + + private static void testNewReaderClose() throws Exception { + Reader reader = null; + try { + ReadableByteChannel channel = new ReadableByteChannel() { + @Override + public int read(ByteBuffer dst) throws IOException { + dst.put((byte)7); + return 1; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() throws IOException { + throw new IOException(); + } + }; + reader = Channels.newReader(channel, + StandardCharsets.UTF_8.newDecoder(), -1); + reader.close(); + } catch (IOException ioe) { + Exception theException = null; + try { + reader.read(); + } catch (Exception e) { + theException = e; + } finally { + if (theException == null) { + throw new RuntimeException("IOException not thrown"); + } else if (!(theException instanceof IOException)) { + throw new RuntimeException("Exception not an IOException: " + + theException); + } else { + String message = theException.getMessage(); + if (!message.equals("Stream closed")) { + throw new RuntimeException("Unexpected message " + + message); + } + } + } + } + } } class ExtendedFileInputStream extends java.io.FileInputStream { diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/nio/file/attribute/BasicFileAttributeView/UnixSocketFile.java --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/UnixSocketFile.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/UnixSocketFile.java Fri Apr 19 08:00:42 2019 -0400 @@ -61,6 +61,14 @@ return; } + // Verify that 'nc' accepts '-U' for Unix domain sockets. + // Skip the test if it is not. + Process procHelp = Runtime.getRuntime().exec(CMD_BASE + " -h"); + if (procHelp.waitFor() != 0) { + System.err.println("Netcat does not accept required options; skipping test."); + return; + } + // Create a new sub-directory of the nominal test directory in which // 'nc' will create the socket file. String testSubDir = System.getProperty("test.dir", ".") diff -r 221a589c52ee -r 4649818834e0 test/jdk/java/rmi/registry/nonLocalRegistry/NonLocalSkeletonTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/rmi/registry/nonLocalRegistry/NonLocalSkeletonTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import sun.rmi.server.UnicastRef; +import sun.rmi.transport.LiveRef; +import sun.rmi.transport.tcp.TCPEndpoint; + +import java.lang.reflect.InvocationHandler; + +import java.lang.reflect.Proxy; +import java.net.InetAddress; +import java.rmi.AccessException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ObjID; +import java.rmi.server.RemoteObjectInvocationHandler; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Set; + + +/* @test + * @bug 8218453 + * @library ../../testlibrary + * @modules java.rmi/sun.rmi.registry:+open java.rmi/sun.rmi.server:+open + * java.rmi/sun.rmi.transport:+open java.rmi/sun.rmi.transport.tcp:+open + * @summary Verify that Registry rejects non-local access for bind, unbind, rebind. + * The test is manual because the (non-local) host running rmiregistry must be supplied as a property. + * @run main/othervm -Dregistry.host=localhost NonLocalSkeletonTest + */ + +/* + * @test + * @library ../../testlibrary + * @modules java.rmi/sun.rmi.registry:+open java.rmi/sun.rmi.server:+open + * java.rmi/sun.rmi.transport:+open java.rmi/sun.rmi.transport.tcp:+open + * @summary Verify that Registry rejects non-local access for bind, unbind, rebind. + * The test is manual because the (non-local) host running rmiregistry must be supplied as a property. + * @run main/othervm/manual -Dregistry.host=rmi-registry-host NonLocalSkeletonTest + */ + +/** + * Verify that access checks for Registry.bind(), .rebind(), and .unbind() + * are prevented on remote access to the registry. + * + * This test is a manual test and uses a standard rmiregistry running + * on a *different* host. + * The test verifies that the access check is performed *before* the object to be + * bound or rebound is deserialized. + * + * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmiregistry}. + * It will not show any output. + * + * On the first host modify the @run command above to replace "rmi-registry-host" + * with the hostname or IP address of the different host and run the test with jtreg. + */ +public class NonLocalSkeletonTest { + + public static void main(String[] args) throws Exception { + String host = System.getProperty("registry.host"); + if (host == null || host.isEmpty()) { + throw new RuntimeException("supply a remote host with -Dregistry.host=hostname"); + } + + // Check if running the test on a local system; it only applies to remote + String myHostName = InetAddress.getLocalHost().getHostName(); + Set myAddrs = Set.of(InetAddress.getAllByName(myHostName)); + Set hostAddrs = Set.of(InetAddress.getAllByName(host)); + boolean isLocal = (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i)) + || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())); + + int port; + if (isLocal) { + // Create a local Registry to use for the test + port = TestLibrary.getUnusedRandomPort(); + Registry registry = LocateRegistry.createRegistry(port); + System.out.printf("local registry port: %s%n", registry); + } else { + // Use regular rmi registry for non-local test + port = Registry.REGISTRY_PORT; + } + + try { + + Registry r = nonStaticRegistryProxy(host, port); + + System.out.printf("RegistryRef: %s%n", r); + + r.rebind("anyRef", r); + if (!isLocal) { + throw new RuntimeException("non-local bind should have failed to host: " + host); + } else { + System.out.printf("local rebind succeeded%n"); + } + } catch (RemoteException rex) { + if (!isLocal) { + assertIsAccessException(rex); + } else { + throw rex; + } + } + } + + /* Returns a non-static proxy for the registry. + * Follows the form of sun.rmi.server.Util.createProxy. + * @param implClass the RegistryImpl + * @param clientRef the registry reference + **/ + static Registry nonStaticRegistryProxy(String host, int port) { + final ClassLoader loader = Registry.class.getClassLoader(); + final Class[] interfaces = new Class[]{Registry.class}; + + LiveRef liveRef = new LiveRef(new ObjID(ObjID.REGISTRY_ID), + new TCPEndpoint(host, port, null, null), + false); + + final InvocationHandler handler = new RemoteObjectInvocationHandler(new UnicastRef(liveRef)); + + PrivilegedAction action = () -> (Registry) Proxy.newProxyInstance(loader, + interfaces, handler); + return AccessController.doPrivileged(action); + } + + /** + * Check the exception chain for the expected AccessException and message. + * @param ex the exception from the remote invocation. + */ + private static void assertIsAccessException(Throwable ex) { + Throwable t = ex; + while (!(t instanceof AccessException) && t.getCause() != null) { + t = t.getCause(); + } + if (t instanceof AccessException) { + String msg = t.getMessage(); + int asIndex = msg.indexOf("Registry"); + int rrIndex = msg.indexOf("Registry.Registry"); // Obsolete error text + int disallowIndex = msg.indexOf("disallowed"); + int nonLocalHostIndex = msg.indexOf("non-local host"); + if (asIndex < 0 || + rrIndex != -1 || + disallowIndex < 0 || + nonLocalHostIndex < 0 ) { + throw new RuntimeException("exception message is malformed", t); + } + System.out.printf("Found expected AccessException: %s%n%n", t); + } else { + throw new RuntimeException("AccessException did not occur when expected", ex); + } + } +} diff -r 221a589c52ee -r 4649818834e0 test/jdk/javax/net/ssl/SSLSocket/InputStreamClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/javax/net/ssl/SSLSocket/InputStreamClosure.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +// +// Please run in othervm mode. SunJSSE does not support dynamic system +// properties, no way to re-use system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 8216326 + * @modules jdk.crypto.ec + * @library /javax/net/ssl/templates + * @summary SSLSocket stream close() does not close the associated socket + * @run main/othervm InputStreamClosure + */ +import java.io.InputStream; +import java.io.OutputStream; +import javax.net.ssl.SSLSocket; + +public class InputStreamClosure extends SSLSocketTemplate { + + // Run the test case. + public static void main(String[] args) throws Exception { + (new InputStreamClosure()).run(); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + // here comes the test logic + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + + /* + * Define the client side application of the test for the specified socket. + * This method is used if the returned value of + * isCustomizedClientConnection() is false. + * + * @param socket may be null is no client socket is generated. + * + * @see #isCustomizedClientConnection() + */ + protected void runClientApplication(SSLSocket socket) throws Exception { + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + + sslIS.close(); + if (!socket.isClosed()) { + throw new Exception("Closing the SSLSocket InputStream does " + + "not close the associated socket"); + } + } +} diff -r 221a589c52ee -r 4649818834e0 test/jdk/javax/net/ssl/SSLSocket/OutputStreamClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/javax/net/ssl/SSLSocket/OutputStreamClosure.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +// +// Please run in othervm mode. SunJSSE does not support dynamic system +// properties, no way to re-use system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 8216326 + * @modules jdk.crypto.ec + * @library /javax/net/ssl/templates + * @summary SSLSocket stream close() does not close the associated socket + * @run main/othervm OutputStreamClosure + */ +import java.io.InputStream; +import java.io.OutputStream; +import javax.net.ssl.SSLSocket; + +public class OutputStreamClosure extends SSLSocketTemplate { + + // Run the test case. + public static void main(String[] args) throws Exception { + (new OutputStreamClosure()).run(); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + // here comes the test logic + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + + /* + * Define the client side application of the test for the specified socket. + * This method is used if the returned value of + * isCustomizedClientConnection() is false. + * + * @param socket may be null is no client socket is generated. + * + * @see #isCustomizedClientConnection() + */ + protected void runClientApplication(SSLSocket socket) throws Exception { + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + + sslOS.close(); + if (!socket.isClosed()) { + throw new Exception("Closing the SSLSocket OutputStream does " + + "not close the associated socket"); + } + } +} diff -r 221a589c52ee -r 4649818834e0 test/jdk/tools/launcher/Settings.java --- a/test/jdk/tools/launcher/Settings.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/tools/launcher/Settings.java Fri Apr 19 08:00:42 2019 -0400 @@ -68,6 +68,7 @@ private static final String PROP_SETTINGS = "Property settings:"; private static final String LOCALE_SETTINGS = "Locale settings:"; private static final String SYSTEM_SETTINGS = "Operating System Metrics:"; + private static final String STACKSIZE_SETTINGS = "Stack Size:"; static void containsAllOptions(TestResult tr) { checkContains(tr, VM_SETTINGS); @@ -82,10 +83,22 @@ int stackSize = 256; // in kb if (getArch().equals("ppc64") || getArch().equals("ppc64le")) { stackSize = 800; + } else if (getArch().equals("aarch64")) { + /* + * The max value of minimum stack size allowed for aarch64 can be estimated as + * such: suppose the vm page size is 64KB and the test runs with a debug build, + * the initial _java_thread_min_stack_allowed defined in os_linux_aarch64.cpp is + * 72K, stack guard zones could take 192KB, and the shadow zone needs 128KB, + * after aligning up all parts to the page size, the final size would be 448KB. + * See details in JDK-8163363 + */ + stackSize = 448; } TestResult tr; tr = doExec(javaCmd, "-Xms64m", "-Xmx512m", "-Xss" + stackSize + "k", "-XshowSettings", "-jar", testJar.getAbsolutePath()); + // Check the stack size logs printed by -XshowSettings to verify -Xss meaningfully. + checkContains(tr, STACKSIZE_SETTINGS); containsAllOptions(tr); if (!tr.isOK()) { System.out.println(tr); @@ -93,6 +106,7 @@ } tr = doExec(javaCmd, "-Xms65536k", "-Xmx712m", "-Xss" + (stackSize * 1024), "-XshowSettings", "-jar", testJar.getAbsolutePath()); + checkContains(tr, STACKSIZE_SETTINGS); containsAllOptions(tr); if (!tr.isOK()) { System.out.println(tr); diff -r 221a589c52ee -r 4649818834e0 test/jdk/tools/launcher/TooSmallStackSize.java --- a/test/jdk/tools/launcher/TooSmallStackSize.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/jdk/tools/launcher/TooSmallStackSize.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6762191 + * @bug 6762191 8222334 * @summary Setting stack size to 16K causes segmentation fault * @compile TooSmallStackSize.java * @run main TooSmallStackSize @@ -171,5 +171,11 @@ * asserts added for 8176768 are not triggered. */ checkMinStackAllowed("513k"); + + /* + * Try with 0k which indicates that the default thread stack size either from JVM or system + * will be used, this should always succeed. + */ + checkMinStackAllowed("0k"); } } diff -r 221a589c52ee -r 4649818834e0 test/jtreg-ext/requires/VMProps.java diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -59,7 +59,7 @@ .classes(classPath.toString()) .run() .getOutput(Task.OutputKind.DIRECT); - if (!javapOut.contains("0: #21(): CLASS_EXTENDS, type_index=65535")) + if (!javapOut.contains("0: #22(): CLASS_EXTENDS, type_index=65535")) throw new AssertionError("Expected output missing: " + javapOut); } } \ No newline at end of file diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -74,14 +74,14 @@ // Expected output can't be directly encoded into NestedLambdasCastedTest !!! static class OutputExpectedOnceHolder { public String[] outputs = { - "0: #61(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]", - "1: #61(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]", + "0: #120(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]", + "1: #120(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]", }; } static class OutputExpectedTwiceHolder { public String[] outputs = { - "0: #61(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]", + "0: #120(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]", }; } diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -53,10 +53,10 @@ "private static strictfp void lambda$main$2();", "private static strictfp void lambda$main$1();", "private static strictfp void lambda$main$0();", - "0: #62(#63=s#64): CAST, offset=5, type_index=0", - "0: #62(#63=s#69): CAST, offset=5, type_index=0", - "0: #62(#63=s#72): CAST, offset=5, type_index=0", - "0: #62(#63=s#75): CAST, offset=5, type_index=0" + "0: #111(#112=s#113): CAST, offset=5, type_index=0", + "0: #111(#112=s#119): CAST, offset=5, type_index=0", + "0: #111(#112=s#122): CAST, offset=5, type_index=0", + "0: #111(#112=s#125): CAST, offset=5, type_index=0" }; } diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/diags/examples.not-yet.txt --- a/test/langtools/tools/javac/diags/examples.not-yet.txt Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt Fri Apr 19 08:00:42 2019 -0400 @@ -46,6 +46,7 @@ compiler.misc.bad.class.signature # bad class file compiler.misc.bad.const.pool.tag # bad class file compiler.misc.bad.const.pool.tag.at # bad class file +compiler.misc.bad.const.pool.index # bad class file compiler.misc.bad.constant.range # bad class file compiler.misc.bad.constant.value # bad class file compiler.misc.bad.enclosing.class # bad class file diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java --- a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java Fri Apr 19 08:00:42 2019 -0400 @@ -61,6 +61,7 @@ import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCIdent; @@ -190,7 +191,7 @@ Symbol oldSym = ident.sym; if (!oldSym.isConstructor()) { ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, - oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]); + oldSym.owner, bsm.asHandle(), oldSym.type, new LoadableConstant[0]); } return null; } diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/lambda/TestInvokeDynamic.java --- a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java Fri Apr 19 08:00:42 2019 -0400 @@ -60,26 +60,23 @@ import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.Method; -import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.MethodHandleSymbol; import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.jvm.Pool; +import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCIdent; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Names; import combo.ComboParameter; -import combo.ComboTask; import combo.ComboTestHelper; import combo.ComboInstance; import combo.ComboTask.Result; -import static com.sun.tools.javac.jvm.ClassFile.*; - public class TestInvokeDynamic extends ComboInstance { enum StaticArgumentKind implements ComboParameter { @@ -168,21 +165,24 @@ abstract boolean check(CPInfo cpInfo) throws Exception; - Object getValue(Symtab syms, Names names, Types types) { + LoadableConstant getValue(Symtab syms) { switch (this) { case STRING: + return LoadableConstant.String((String)value); case INTEGER: + return LoadableConstant.Int((Integer)value); case LONG: + return LoadableConstant.Long((Long)value); case FLOAT: + return LoadableConstant.Float((Float)value); case DOUBLE: - return value; + return LoadableConstant.Double((Double)value); case CLASS: - return syms.stringType.tsym; + return (ClassType)syms.stringType; case METHOD_HANDLE: - return new Pool.MethodHandle(REF_invokeVirtual, - syms.arrayCloneMethod, types); + return syms.arrayCloneMethod.asHandle(); case METHOD_TYPE: - return syms.arrayCloneMethod.type; + return ((MethodType)syms.arrayCloneMethod.type); default: throw new AssertionError(); } @@ -394,7 +394,7 @@ class Indifier extends TreeScanner implements TaskListener { - MethodSymbol bsm; + MethodHandleSymbol bsm; Symtab syms; Names names; Types types; @@ -424,12 +424,12 @@ JCIdent ident = (JCIdent)apply.meth; Symbol oldSym = ident.sym; if (!oldSym.isConstructor()) { - Object[] staticArgs = new Object[arity.arity]; + LoadableConstant[] staticArgs = new LoadableConstant[arity.arity]; for (int i = 0; i < arity.arity ; i++) { - staticArgs[i] = saks[i].getValue(syms, names, types); + staticArgs[i] = saks[i].getValue(syms); } ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, - oldSym.owner, REF_invokeStatic, bsm, oldSym.type, staticArgs); + oldSym.owner, bsm, oldSym.type, staticArgs); } return null; } @@ -438,7 +438,7 @@ public Void visitMethod(MethodTree node, Void p) { super.visitMethod(node, p); if (node.getName().toString().equals("bsm")) { - bsm = ((JCMethodDecl)node).sym; + bsm = ((JCMethodDecl)node).sym.asHandle(); } return null; } diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out --- a/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out Fri Apr 19 08:00:42 2019 -0400 @@ -1,2 +1,2 @@ -- compiler.err.cant.access: .module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: mod/module-info, )) +- compiler.err.cant.access: .module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.const.pool.index: module-info.class, 15, 10)) 1 error diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java --- a/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java Fri Apr 19 08:00:42 2019 -0400 @@ -90,8 +90,8 @@ "NestHost: class CheckNestmateAttrs", "0: aload_0", "1: getfield #1 // Field this$1:LCheckNestmateAttrs$Inner;", - "4: getfield #3 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;", - "7: invokevirtual #4 // Method CheckNestmateAttrs.test:()V", + "4: getfield #13 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;", + "7: invokevirtual #19 // Method CheckNestmateAttrs.test:()V", "10: return" }); diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/processing/environment/TestPreviewEnabled.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/processing/environment/TestPreviewEnabled.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8222378 + * @summary Test that ProcessingEnvironment.isPreviewEnabled works properly + * @library /tools/javac/lib + * @modules java.compiler + * @build JavacTestingAbstractProcessor + * @compile TestPreviewEnabled.java + * @compile -processor TestPreviewEnabled -proc:only -source ${jdk.version} -AExpectedPreview=false TestSourceVersion.java + * @compile -processor TestPreviewEnabled -proc:only -source ${jdk.version} -AExpectedPreview=true --enable-preview TestSourceVersion.java + */ + +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import javax.annotation.processing.*; +import javax.lang.model.util.*; + +/** + * This processor checks that ProcessingEnvironment.isPreviewEnabled + * is consistent with the compiler options. + */ +@SupportedOptions("ExpectedPreview") +public class TestPreviewEnabled extends JavacTestingAbstractProcessor { + public boolean process(Set annotations, + RoundEnvironment roundEnvironment) { + if (!roundEnvironment.processingOver()) { + boolean expectedPreview = + Boolean.valueOf(processingEnv.getOptions().get("ExpectedPreview")); + boolean actualPreview = processingEnv.isPreviewEnabled(); + System.out.println("Expected PreviewEnabled: " + expectedPreview + + "\n actual PreviewEnabled: " + actualPreview); + if (expectedPreview != actualPreview) + throw new RuntimeException(); + + if (expectedPreview) { + // Create a ProcessingEnvironment that uses the + // default implemention of isPreviewEnabled. + ProcessingEnvironment testEnv = new ProcessingEnvironment() { + @Override public Elements getElementUtils() {return null;} + @Override public Filer getFiler() {return null;} + @Override public Locale getLocale() {return null;} + @Override public Messager getMessager() {return null;} + @Override public Map getOptions() {return null;} + @Override public SourceVersion getSourceVersion() {return null;} + @Override public Types getTypeUtils() {return null;} + }; + if (testEnv.isPreviewEnabled()) { + throw new RuntimeException("Bad true return value from default " + + "ProcessingEnvironment.isPreviewEnabled."); + } + } + } + return true; + } +} diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java Fri Apr 19 08:00:42 2019 -0400 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8222430 + * @summary Test various predicates of ElementKind. + */ + +import java.util.Set; +import java.util.function.Predicate; +import javax.lang.model.element.ElementKind; + +/** + * Test the isClass, isField, and isInterface predicates of ElementKind. + */ +public class TestElementKindPredicates { + public static void main(String... args) { + Set ALL_KINDS = Set.of(ElementKind.values()); + + // isClass: Returns true if this is a kind of class: either CLASS or ENUM. + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.CLASS, + ElementKind.ENUM).contains(k), + (ElementKind k) -> k.isClass(), "isClass"); + + // isField: Returns true if this is a kind of field: either FIELD or ENUM_CONSTANT. + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.FIELD, + ElementKind.ENUM_CONSTANT).contains(k), + (ElementKind k) -> k.isField(), "isField"); + + // isInterface: Returns true if this is a kind of interface: either INTERFACE or ANNOTATION_TYPE. + test(ALL_KINDS, + (ElementKind k) -> Set.of(ElementKind.INTERFACE, + ElementKind.ANNOTATION_TYPE).contains(k), + (ElementKind k) -> k.isInterface(), "isInterface"); + } + + private static void test(Set kinds, + Predicate expectedPred, + Predicate actualPred, + String errorMessage) { + for(ElementKind kind : kinds) { + boolean expected = expectedPred.test(kind); + boolean actual = actualPred.test(kind); + + if (expected != actual) { + throw new RuntimeException("Error testing ElementKind." + errorMessage + "(" + kind + + "):\texpected " + expected + "\tgot " + actual); + } + } + } +} diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javap/AnnoTest.java --- a/test/langtools/tools/javap/AnnoTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javap/AnnoTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -49,50 +49,50 @@ expect(out, "RuntimeVisibleAnnotations:\n" + - " 0: #18(#19=B#20)\n" + + " 0: #21(#22=B#23)\n" + " AnnoTest$ByteAnno(\n" + " value=(byte) 42\n" + " )\n" + - " 1: #23(#19=S#24)\n" + + " 1: #24(#22=S#25)\n" + " AnnoTest$ShortAnno(\n" + " value=(short) 3\n" + " )"); expect(out, "RuntimeInvisibleAnnotations:\n" + - " 0: #28(#19=[J#29,J#31,J#33,J#35,J#37])\n" + + " 0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" + " AnnoTest$ArrayAnno(\n" + " value=[1l,2l,3l,4l,5l]\n" + " )\n" + - " 1: #41(#19=Z#42)\n" + + " 1: #38(#22=Z#39)\n" + " AnnoTest$BooleanAnno(\n" + " value=false\n" + " )\n" + - " 2: #45(#46=c#47)\n" + + " 2: #40(#41=c#42)\n" + " AnnoTest$ClassAnno(\n" + " type=class Ljava/lang/Object;\n" + " )\n" + - " 3: #50(#51=e#52.#53)\n" + + " 3: #43(#44=e#45.#46)\n" + " AnnoTest$EnumAnno(\n" + " kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" + " )\n" + - " 4: #56(#19=I#57)\n" + + " 4: #47(#22=I#48)\n" + " AnnoTest$IntAnno(\n" + " value=2\n" + " )\n" + - " 5: #60()\n" + + " 5: #49()\n" + " AnnoTest$IntDefaultAnno\n" + - " 6: #63(#64=s#65)\n" + + " 6: #50(#51=s#52)\n" + " AnnoTest$NameAnno(\n" + " name=\"NAME\"\n" + " )\n" + - " 7: #68(#69=D#70,#72=F#73)\n" + + " 7: #53(#54=D#55,#57=F#58)\n" + " AnnoTest$MultiAnno(\n" + " d=3.14159d\n" + " f=2.71828f\n" + " )\n" + - " 8: #76()\n" + + " 8: #59()\n" + " AnnoTest$SimpleAnno\n" + - " 9: #79(#19=@#56(#19=I#80))\n" + + " 9: #60(#22=@#47(#22=I#61))\n" + " AnnoTest$AnnoAnno(\n" + " value=@AnnoTest$IntAnno(\n" + " value=5\n" + @@ -100,7 +100,7 @@ " )"); expect(out, "RuntimeInvisibleTypeAnnotations:\n" + - " 0: #84(): CLASS_EXTENDS, type_index=0\n" + + " 0: #63(): CLASS_EXTENDS, type_index=0\n" + " AnnoTest$TypeAnno"); if (errors > 0) diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java --- a/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -51,7 +51,7 @@ private static final String ExpectedSubstring = " AnnotationDefault:\n" + - " default_value: I#7\n"; + " default_value: I#9\n"; public static void main(String[] args) throws Exception { ToolBox tb = new ToolBox(); diff -r 221a589c52ee -r 4649818834e0 test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java --- a/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java Fri Apr 19 08:00:42 2019 -0400 @@ -62,11 +62,11 @@ " RuntimeVisibleParameterAnnotations:\n" + " parameter 0:\n" + " parameter 1:\n" + - " 0: #16()\n" + + " 0: #14()\n" + " Sample$VisAnno\n" + " RuntimeInvisibleParameterAnnotations:\n" + " parameter 0:\n" + - " 0: #18()\n" + + " 0: #16()\n" + " Sample$InvisAnno\n" + " parameter 1:"; diff -r 221a589c52ee -r 4649818834e0 test/lib/jdk/test/lib/process/OutputAnalyzer.java --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ import java.io.IOException; import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -59,6 +61,15 @@ /** * Create an OutputAnalyzer, a utility class for verifying output * + * @param file File to analyze + */ + public OutputAnalyzer(Path file) throws IOException { + this(Files.readString(file)); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * * @param stdout stdout buffer to analyze * @param stderr stderr buffer to analyze */ diff -r 221a589c52ee -r 4649818834e0 test/micro/org/openjdk/bench/java/lang/StringConcat.java --- a/test/micro/org/openjdk/bench/java/lang/StringConcat.java Fri Apr 19 07:55:28 2019 -0400 +++ b/test/micro/org/openjdk/bench/java/lang/StringConcat.java Fri Apr 19 08:00:42 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,11 @@ } @Benchmark + public String concatMethodConstString() { + return "string".concat(stringValue); + } + + @Benchmark public String concatConstIntConstInt() { return "string" + intValue + "string" + intValue; }