diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 07b5d34491..ef1c8f02c3 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -417,9 +417,38 @@ b25838a28195f4b6dab34668411eedd2d366a16c jdk-9+169 2c25fc24103251f9711a1c280c31e1e41016d90f jdk-9+172 88d7fd969e7df0e07a53b201cfd29393ca33ede9 jdk-9+173 5466f409346e0446ee9a6daeb7f5d75c8fc76823 jdk-9+174 +023f93e511bae768203c33bb8681f82ee75014da jdk-9.0.1+00 +023f93e511bae768203c33bb8681f82ee75014da jdk-9.0.3+00 8f7227c6012b0051ea4e0bcee040c627bf699b88 jdk-9+175 84777531d994ef70163d35078ec9c4127f2eadb5 jdk-9+176 a4371edb589c60db01142e45c317adb9ccbcb083 jdk-9+177 ec4159ebe7050fcc5dcee8a2d150cf948ecc97db jdk-9+178 252475ccfd84cc249f8d6faf4b7806b5e2c384ce jdk-9+179 d2982a786f53814367698e63efe6349c9128e1db jdk-9+180 +b656dea9398ef601f7fc08d1a5157a560e0ccbe0 jdk-9+181 +d73368c690d4f1ab188cf306f4b27218e28596b6 jdk-9.0.3+1 +ede48839f34b0b74210e2e081872a3c12d5339ab jdk-9.0.3+2 +086e9950ebfa8a0239018ade61f59b7c539bacc9 jdk-9.0.3+3 +2c95bee2722f2396b709b384473c07291a7d1e4b jdk-9.0.3+4 +d24281b60e0bb6d441ec3a9440e7daa322bbc822 jdk-9.0.3+5 +489c57f8e1c0f6fa34de86f8ed8f98a809cba4a9 jdk-9.0.3+6 +9d5aca497123931d52625b3539a8549d98728622 jdk-9.0.3+7 +eaa4ea516c7f1e31c8e0faaec3ef981eb2919ae3 jdk-9.0.3+8 +a31dfd85bee9c16aac1e65dfbe81d1c5fe443c2c jdk-9.0.3+9 +9acb1002f33e257e932a188632969e45cc32e66c jdk-9.0.1+10 +9acb1002f33e257e932a188632969e45cc32e66c jdk-9.0.1+10 +0000000000000000000000000000000000000000 jdk-9.0.1+10 +0000000000000000000000000000000000000000 jdk-9.0.1+10 +5a9191c980ca3ada63b234e2b9ec6dc23bd37595 jdk-9.0.1+10 +e6edc89f5b2dc6dacd6041305e942a3f04a25ce5 jdk-9.0.1+11 +3a64fdb24a8c26e2d7d32864dad4425a9496b90d jdk-9.0.4+00 +726bf8524f7d3780518ada8648488ad4a7bfe6a2 jdk-9.0.4+1 +8055b6778ac8fc6bb165082230951cc8f146f8fd jdk-9.0.4+2 +572ea0db1d87a1d2fcc01f73ffbcfb78bd5688f4 jdk-9.0.4+3 +0053ace2e9e484fb52d00ec961e24805d0aae04a jdk-9.0.4+4 +73d63ccf56f46f258f367ed72633f0f5cc229680 jdk-9.0.4+5 +86219e4c9f8cd730bacd2f6080b6ac1dea7a0226 jdk-9.0.4+6 +9aba57f3071362ed7f2326d737506863b9d2646f jdk-9.0.4+7 +a4f0515fe6da55cfe74dec3e6e30b69c9693d133 jdk-9.0.4+8 +a4f0515fe6da55cfe74dec3e6e30b69c9693d133 jdk-9.0.4+8 +0000000000000000000000000000000000000000 jdk-9.0.4+8 diff --git a/.jcheck/conf b/.jcheck/conf index 5c6f62dc12..9bd9e92741 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1 +1,2 @@ project=jdk9 +bugids=dup diff --git a/common/autoconf/version-numbers b/common/autoconf/version-numbers index 4cb5467118..84a962fa81 100644 --- a/common/autoconf/version-numbers +++ b/common/autoconf/version-numbers @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ DEFAULT_VERSION_MAJOR=9 DEFAULT_VERSION_MINOR=0 -DEFAULT_VERSION_SECURITY=0 +DEFAULT_VERSION_SECURITY=4 DEFAULT_VERSION_PATCH=0 LAUNCHER_NAME=openjdk diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index 54ccfcecd5..53070dc129 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -387,7 +387,7 @@ var getJibProfilesCommon = function (input, data) { // on such hardware. if (input.build_cpu == "sparcv9") { var cpu_brand = $EXEC("bash -c \"kstat -m cpu_info | grep brand | head -n1 | awk '{ print \$2 }'\""); - if (cpu_brand.trim().match('SPARC-.7')) { + if (cpu_brand.trim().match('SPARC-.[78]')) { boot_jdk_revision = "8u20"; boot_jdk_subdirpart = "1.8.0_20"; } @@ -814,41 +814,84 @@ var getJibProfilesProfiles = function (input, common, data) { } }, - "windows-x86-open": { + "macosx-x64-open": { artifacts: { jdk: { local: "bundles/\\(jdk.*bin.tar.gz\\)", remote: [ - "bundles/openjdk/GPL/windows-x86/jdk-" + data.version - + "_windows-x86_bin.tar.gz", - "bundles/openjdk/GPL/windows-x86/\\1" + "bundles/openjdk/GPL/osx-x64/jdk-" + data.version + + "_osx-x64_bin.tar.gz", + "bundles/openjdk/GPL/osx-x64/\\1" ], subdir: "jdk-" + data.version }, jre: { local: "bundles/\\(jre.*bin.tar.gz\\)", - remote: "bundles/openjdk/GPL/windows-x86/\\1" + remote: "bundles/openjdk/GPL/osx-x64/\\1", }, test: { local: "bundles/\\(jdk.*bin-tests.tar.gz\\)", remote: [ - "bundles/openjdk/GPL/windows-x86/jdk-" + data.version - + "_windows-x86_bin-tests.tar.gz", - "bundles/openjdk/GPL/windows-x86/\\1" + "bundles/openjdk/GPL/osx-x64/jdk-" + data.version + + "_osx-x64_bin-tests.tar.gz", + "bundles/openjdk/GPL/osx-x64/\\1" ] }, jdk_symbols: { local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", remote: [ - "bundles/openjdk/GPL/windows-x86/jdk-" + data.version - + "_windows-x86_bin-symbols.tar.gz", - "bundles/openjdk/GPL/windows-x86/\\1" + "bundles/openjdk/GPL/osx-x64/jdk-" + data.version + + "_osx-x64_bin-symbols.tar.gz", + "bundles/openjdk/GPL/osx-x64/\\1" ], subdir: "jdk-" + data.version }, jre_symbols: { local: "bundles/\\(jre.*bin-symbols.tar.gz\\)", - remote: "bundles/openjdk/GPL/windows-x86/\\1", + remote: "bundles/openjdk/GPL/osx-x64/\\1", + }, + doc_api_spec: { + local: "bundles/\\(jdk.*doc-api-spec.tar.gz\\)", + remote: "bundles/openjdk/GPL/osx-x64/\\1", + }, + } + }, + + "windows-x64-open": { + artifacts: { + jdk: { + local: "bundles/\\(jdk.*bin.tar.gz\\)", + remote: [ + "bundles/openjdk/GPL/windows-x64/jdk-" + data.version + + "_windows-x64_bin.tar.gz", + "bundles/openjdk/GPL/windows-x64/\\1" + ], + subdir: "jdk-" + data.version + }, + jre: { + local: "bundles/\\(jre.*bin.tar.gz\\)", + remote: "bundles/openjdk/GPL/windows-x64/\\1" + }, + test: { + local: "bundles/\\(jdk.*bin-tests.tar.gz\\)", + remote: [ + "bundles/openjdk/GPL/windows-x64/jdk-" + data.version + + "_windows-x64_bin-tests.tar.gz", + "bundles/openjdk/GPL/windows-x64/\\1" + ] + }, + jdk_symbols: { + local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", + remote: [ + "bundles/openjdk/GPL/windows-x64/jdk-" + data.version + + "_windows-x64_bin-symbols.tar.gz", + "bundles/openjdk/GPL/windows-x64/\\1" + ], + subdir: "jdk-" + data.version + }, + jre_symbols: { + local: "bundles/\\(jre.*bin-symbols.tar.gz\\)", + remote: "bundles/openjdk/GPL/windows-x64/\\1", } } }, @@ -880,10 +923,11 @@ var getJibProfilesProfiles = function (input, common, data) { profiles["linux-x64-ri"] = clone(profiles["linux-x64-open"]); profiles["linux-x86-ri"] = clone(profiles["linux-x86-open"]); profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]); - profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]); + profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]); + profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]); // Generate artifacts for ri profiles - [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "windows-x86-ri" ] + [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x64-ri" ] .forEach(function (name) { // Rewrite all remote dirs to "bundles/openjdk/BCL/..." for (artifactName in profiles[name].artifacts) { @@ -895,10 +939,10 @@ var getJibProfilesProfiles = function (input, common, data) { // The windows ri profile needs to add the freetype license file profilesRiFreetype = { - "windows-x86-ri": { + "windows-x64-ri": { configure_args: "--with-freetype-license=" + input.get("freetype", "install_path") - + "/freetype-2.7.1-v120-x86/freetype.md" + + "/freetype-2.7.1-v120-x64/freetype.md" } }; profiles = concatObjects(profiles, profilesRiFreetype); @@ -1200,7 +1244,8 @@ var versionArgs = function(input, common) { if (input.build_type == "promoted") { args = concat(args, // This needs to be changed when we start building release candidates - "--with-version-pre=ea", + // 'ea' for EA builds and empty value for 'fcs' + "--with-version-pre=", "--without-version-opt"); } else { args = concat(args, "--with-version-opt=" + common.build_id); diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 3e06b395fe..fe0da5a280 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -577,9 +577,31 @@ d53171650a2cc6c6f699c966c533b914ca9c0602 jdk-9+171 1ae9e84f68b359420d2d153ecfe5ee2903e33a2e jdk-9+172 e64b1cb48d6e7703928a9d1da106fc27f8cb65fd jdk-9+173 944791f8160185bffa13fbb821fc09b6198f1f25 jdk-9+174 +ca47dcfdd35129fe3ab2dab71b2601d7a0ff07c0 jdk-9.0.1+00 +ca47dcfdd35129fe3ab2dab71b2601d7a0ff07c0 jdk-9.0.3+00 8f04d457168b9f1f4a1b2c37f49e0513ca9d33a7 jdk-9+175 2ab74e5dbdc2b6a962c865500cafd23cf387dc60 jdk-9+176 1ca8f038fceb88c640badf9bd18905205bc63b43 jdk-9+177 9d032191f82fca5ba0aac98682f69c4ff0f1283d jdk-9+178 d2661aa42bff322badbe6c1337fc638d2e0f5730 jdk-9+179 d7baadc223e790c08bc69bf7e553bce65b4e7e40 jdk-9+180 +4a443796f6f57842d6a0434ac27ca3d1033ccc20 jdk-9+181 +8297b62a7b62bafe42c7d567a5752f7a82bafab8 jdk-9.0.3+1 +d2efdbb193a02613867c8949f783d2905f7a28fc jdk-9.0.3+2 +68f9ff7c5eedfd41f9c10959e41024efbd3aa79c jdk-9.0.3+3 +82584ea6464de2e0a59e9fc00173e18a85dc45d8 jdk-9.0.3+4 +c45e75533bae7b5db5c626bf9233b4226934d582 jdk-9.0.3+5 +4c0248d117fabf46c5931cdd09e543c3d89b68a5 jdk-9.0.3+6 +fca264c9fa3ce57b3f4d662242d38b44fb442c87 jdk-9.0.3+7 +1f5a9c0ddb4b8da443f70fc5d135b320f6e0b78a jdk-9.0.3+8 +a10c11fed5bdc5202523baee3cf391cc0e0cfcaa jdk-9.0.3+9 +172baf6c99c5e9fdd72a6f3729f6ec8cd6b48183 jdk-9.0.1+10 +3546eb2ee2693043eb107d980ce5b72fe7f8f47a jdk-9.0.1+11 +5be37d3ef648d06850aa164d8b22ac7539559e80 jdk-9.0.4+00 +46290b7298be50f9a70d27465d50d1675732f0af jdk-9.0.4+1 +dab4c60adabfb8ea35cfcd96a7218994a84d652f jdk-9.0.4+2 +deed95e4b4cba997b3cc13b62e33615fd11bc902 jdk-9.0.4+3 +ce49d719fd4d5f0ff12a1906d9d8b651a7a7d60c jdk-9.0.4+4 +11116cc619ac1b0d00cdcd47e8a7eb2339207bbf jdk-9.0.4+5 +f3ba0e190ffcc82f1ed0dd8275a51096123514b6 jdk-9.0.4+6 +e020892c9b441ff0855479ad4de63a9eb4b59bf7 jdk-9.0.4+7 diff --git a/hotspot/.jcheck/conf b/hotspot/.jcheck/conf index 5c6f62dc12..9bd9e92741 100644 --- a/hotspot/.jcheck/conf +++ b/hotspot/.jcheck/conf @@ -1 +1,2 @@ project=jdk9 +bugids=dup diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index a286102e7b..f12334291e 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -773,7 +773,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm __ load_klass(rscratch1, receiver); __ ldr(tmp, Address(holder, CompiledICHolder::holder_klass_offset())); __ cmp(rscratch1, tmp); - __ ldr(rmethod, Address(holder, CompiledICHolder::holder_method_offset())); + __ ldr(rmethod, Address(holder, CompiledICHolder::holder_metadata_offset())); __ br(Assembler::EQ, ok); __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp index 2eb2a55100..d09c84b85f 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp @@ -2475,49 +2475,65 @@ void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in // On success, the result will be in method_result, and execution falls through. // On failure, execution transfers to the given label. void MacroAssembler::lookup_interface_method(Register Rklass, - Register Rinterf, - Register Rindex, + Register Rintf, + RegisterOrConstant itable_index, Register method_result, - Register temp_reg1, - Register temp_reg2, + Register Rscan, + Register Rtmp, Label& L_no_such_interface) { - assert_different_registers(Rklass, Rinterf, temp_reg1, temp_reg2, Rindex); + assert_different_registers(Rklass, Rintf, Rscan, Rtmp); - Register Ritable = temp_reg1; + const int entry_size = itableOffsetEntry::size() * HeapWordSize; + assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience"); // Compute start of first itableOffsetEntry (which is at the end of the vtable) const int base = in_bytes(Klass::vtable_start_offset()); const int scale = exact_log2(vtableEntry::size_in_bytes()); - ldr_s32(temp_reg2, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable - add(Ritable, Rklass, base); - add(Ritable, Ritable, AsmOperand(temp_reg2, lsl, scale)); + ldr_s32(Rtmp, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable + add(Rscan, Rklass, base); + add(Rscan, Rscan, AsmOperand(Rtmp, lsl, scale)); - Label entry, search; + // Search through the itable for an interface equal to incoming Rintf + // itable looks like [intface][offset][intface][offset][intface][offset] - b(entry); + Label loop; + bind(loop); + ldr(Rtmp, Address(Rscan, entry_size, post_indexed)); +#ifdef AARCH64 + Label found; + cmp(Rtmp, Rintf); + b(found, eq); + cbnz(Rtmp, loop); +#else + cmp(Rtmp, Rintf); // set ZF and CF if interface is found + cmn(Rtmp, 0, ne); // check if tmp == 0 and clear CF if it is + b(loop, ne); +#endif // AARCH64 - bind(search); - add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize); +#ifdef AARCH64 + b(L_no_such_interface); + bind(found); +#else + // CF == 0 means we reached the end of itable without finding icklass + b(L_no_such_interface, cc); +#endif // !AARCH64 - bind(entry); - - // Check that the entry is non-null. A null entry means that the receiver - // class doesn't implement the interface, and wasn't the same as the - // receiver class checked when the interface was resolved. - - ldr(temp_reg2, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes())); - cbz(temp_reg2, L_no_such_interface); - - cmp(Rinterf, temp_reg2); - b(search, ne); - - ldr_s32(temp_reg2, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes())); - add(temp_reg2, temp_reg2, Rklass); // Add offset to Klass* - assert(itableMethodEntry::size() * HeapWordSize == wordSize, "adjust the scaling in the code below"); - assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust the offset in the code below"); - - ldr(method_result, Address::indexed_ptr(temp_reg2, Rindex)); + if (method_result != noreg) { + // Interface found at previous position of Rscan, now load the method + ldr_s32(Rtmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size)); + if (itable_index.is_register()) { + add(Rtmp, Rtmp, Rklass); // Add offset to Klass* + assert(itableMethodEntry::size() * HeapWordSize == wordSize, "adjust the scaling in the code below"); + assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust the offset in the code below"); + ldr(method_result, Address::indexed_ptr(Rtmp, itable_index.as_register())); + } else { + int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index.as_constant() + + itableMethodEntry::method_offset_in_bytes(); + add_slow(method_result, Rklass, method_offset); + ldr(method_result, Address(method_result, Rtmp)); + } + } } #ifdef COMPILER2 diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp index e6f73353cb..1a098fdbfb 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp @@ -1316,7 +1316,7 @@ public: void lookup_interface_method(Register recv_klass, Register intf_klass, - Register itable_index, + RegisterOrConstant itable_index, Register method_result, Register temp_reg1, Register temp_reg2, diff --git a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp index 48f096473c..f2413d01a3 100644 --- a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp +++ b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp @@ -987,7 +987,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm __ load_klass(receiver_klass, receiver); __ ldr(holder_klass, Address(Ricklass, CompiledICHolder::holder_klass_offset())); - __ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_method_offset())); + __ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_metadata_offset())); __ cmp(receiver_klass, holder_klass); #ifdef AARCH64 diff --git a/hotspot/src/cpu/arm/vm/templateTable_arm.cpp b/hotspot/src/cpu/arm/vm/templateTable_arm.cpp index c8711b830e..b5acc286f9 100644 --- a/hotspot/src/cpu/arm/vm/templateTable_arm.cpp +++ b/hotspot/src/cpu/arm/vm/templateTable_arm.cpp @@ -4192,7 +4192,7 @@ void TemplateTable::invokeinterface(int byte_no) { const Register Rflags = R3_tmp; const Register Rklass = R3_tmp; - prepare_invoke(byte_no, Rinterf, Rindex, Rrecv, Rflags); + prepare_invoke(byte_no, Rinterf, Rmethod, Rrecv, Rflags); // Special case of invokeinterface called for virtual method of // java.lang.Object. See cpCacheOop.cpp for details. @@ -4201,56 +4201,39 @@ void TemplateTable::invokeinterface(int byte_no) { Label notMethod; __ tbz(Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift, notMethod); - __ mov(Rmethod, Rindex); invokevirtual_helper(Rmethod, Rrecv, Rflags); __ bind(notMethod); // Get receiver klass into Rklass - also a null check __ load_klass(Rklass, Rrecv); + Label no_such_interface; + + // Receiver subtype check against REFC. + __ lookup_interface_method(// inputs: rec. class, interface + Rklass, Rinterf, noreg, + // outputs: scan temp. reg1, scan temp. reg2 + noreg, Ritable, Rtemp, + no_such_interface); + // profile this call __ profile_virtual_call(R0_tmp, Rklass); - // Compute start of first itableOffsetEntry (which is at the end of the vtable) - const int base = in_bytes(Klass::vtable_start_offset()); - assert(vtableEntry::size() == 1, "adjust the scaling in the code below"); - __ ldr_s32(Rtemp, Address(Rklass, Klass::vtable_length_offset())); // Get length of vtable - __ add(Ritable, Rklass, base); - __ add(Ritable, Ritable, AsmOperand(Rtemp, lsl, LogBytesPerWord)); + // Get declaring interface class from method + __ ldr(Rtemp, Address(Rmethod, Method::const_offset())); + __ ldr(Rtemp, Address(Rtemp, ConstMethod::constants_offset())); + __ ldr(Rinterf, Address(Rtemp, ConstantPool::pool_holder_offset_in_bytes())); - Label entry, search, interface_ok; + // Get itable index from method + __ ldr_s32(Rtemp, Address(Rmethod, Method::itable_index_offset())); + __ add(Rtemp, Rtemp, (-Method::itable_index_max)); // small negative constant is too large for an immediate on arm32 + __ neg(Rindex, Rtemp); - __ b(entry); - - __ bind(search); - __ add(Ritable, Ritable, itableOffsetEntry::size() * HeapWordSize); - - __ bind(entry); - - // Check that the entry is non-null. A null entry means that the receiver - // class doesn't implement the interface, and wasn't the same as the - // receiver class checked when the interface was resolved. - - __ ldr(Rtemp, Address(Ritable, itableOffsetEntry::interface_offset_in_bytes())); - __ cbnz(Rtemp, interface_ok); - - // throw exception - __ call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_IncompatibleClassChangeError)); - - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - - __ bind(interface_ok); - - __ cmp(Rinterf, Rtemp); - __ b(search, ne); - - __ ldr_s32(Rtemp, Address(Ritable, itableOffsetEntry::offset_offset_in_bytes())); - __ add(Rtemp, Rtemp, Rklass); // Add offset to Klass* - assert(itableMethodEntry::size() == 1, "adjust the scaling in the code below"); - - __ ldr(Rmethod, Address::indexed_ptr(Rtemp, Rindex)); + __ lookup_interface_method(// inputs: rec. class, interface + Rklass, Rinterf, Rindex, + // outputs: scan temp. reg1, scan temp. reg2 + Rmethod, Ritable, Rtemp, + no_such_interface); // Rmethod: Method* to call @@ -4272,6 +4255,13 @@ void TemplateTable::invokeinterface(int byte_no) { // do the call __ jump_from_interpreted(Rmethod); + + // throw exception + __ bind(no_such_interface); + __ restore_method(); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); } void TemplateTable::invokehandle(int byte_no) { diff --git a/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp b/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp index 8b980aba56..06432c1ee8 100644 --- a/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp +++ b/hotspot/src/cpu/arm/vm/vtableStubs_arm.cpp @@ -28,6 +28,7 @@ #include "code/vtableStubs.hpp" #include "interp_masm_arm.hpp" #include "memory/resourceArea.hpp" +#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -118,67 +119,48 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { // R0-R3 / R0-R7 registers hold the arguments and cannot be spoiled const Register Rclass = AARCH64_ONLY(R9) NOT_AARCH64(R4); - const Register Rlength = AARCH64_ONLY(R10) NOT_AARCH64(R5); + const Register Rintf = AARCH64_ONLY(R10) NOT_AARCH64(R5); const Register Rscan = AARCH64_ONLY(R11) NOT_AARCH64(R6); - const Register tmp = Rtemp; - assert_different_registers(Ricklass, Rclass, Rlength, Rscan, tmp); + assert_different_registers(Ricklass, Rclass, Rintf, Rscan, Rtemp); // Calculate the start of itable (itable goes after vtable) const int scale = exact_log2(vtableEntry::size_in_bytes()); address npe_addr = __ pc(); __ load_klass(Rclass, R0); - __ ldr_s32(Rlength, Address(Rclass, Klass::vtable_length_offset())); - __ add(Rscan, Rclass, in_bytes(Klass::vtable_start_offset())); - __ add(Rscan, Rscan, AsmOperand(Rlength, lsl, scale)); + Label L_no_such_interface; - // Search through the itable for an interface equal to incoming Ricklass - // itable looks like [intface][offset][intface][offset][intface][offset] - const int entry_size = itableOffsetEntry::size() * HeapWordSize; - assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience"); + // Receiver subtype check against REFC. + __ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_klass_offset())); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + Rclass, Rintf, noreg, + // outputs: temp reg1, temp reg2 + noreg, Rscan, Rtemp, + L_no_such_interface); - Label loop; - __ bind(loop); - __ ldr(tmp, Address(Rscan, entry_size, post_indexed)); -#ifdef AARCH64 - Label found; - __ cmp(tmp, Ricklass); - __ b(found, eq); - __ cbnz(tmp, loop); -#else - __ cmp(tmp, Ricklass); // set ZF and CF if interface is found - __ cmn(tmp, 0, ne); // check if tmp == 0 and clear CF if it is - __ b(loop, ne); -#endif // AARCH64 - - assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "Check initialization order"); -#ifdef AARCH64 - __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, tmp); - __ bind(found); -#else - // CF == 0 means we reached the end of itable without finding icklass - __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, noreg, cc); -#endif // !AARCH64 - - // Interface found at previous position of Rscan, now load the method oop - __ ldr_s32(tmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size)); - { - const int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index + - itableMethodEntry::method_offset_in_bytes(); - __ add_slow(Rmethod, Rclass, method_offset); - } - __ ldr(Rmethod, Address(Rmethod, tmp)); + // Get Method* and entry point for compiler + __ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_metadata_offset())); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + Rclass, Rintf, itable_index, + // outputs: temp reg1, temp reg2, temp reg3 + Rmethod, Rscan, Rtemp, + L_no_such_interface); address ame_addr = __ pc(); #ifdef AARCH64 - __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset())); - __ br(tmp); + __ ldr(Rtemp, Address(Rmethod, Method::from_compiled_offset())); + __ br(Rtemp); #else __ ldr(PC, Address(Rmethod, Method::from_compiled_offset())); #endif // AARCH64 + __ bind(L_no_such_interface); + + assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "check initialization order"); + __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp); + masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { @@ -205,7 +187,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { instr_count = NOT_AARCH64(4) AARCH64_ONLY(5); } else { // itable stub size - instr_count = NOT_AARCH64(20) AARCH64_ONLY(20); + instr_count = NOT_AARCH64(31) AARCH64_ONLY(31); } #ifdef AARCH64 diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index dc36aa77da..66d2846a08 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1185,7 +1185,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm // Argument is valid and klass is as expected, continue. // Extract method from inline cache, verified entry point needs it. - __ ld(R19_method, CompiledICHolder::holder_method_offset(), ic); + __ ld(R19_method, CompiledICHolder::holder_metadata_offset(), ic); assert(R19_method == ic, "the inline cache register is dead here"); __ ld(code, method_(code)); diff --git a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp index 89c3ae4032..fefa0411d9 100644 --- a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp +++ b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp @@ -2628,9 +2628,9 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label skip_fixup; { Label ic_miss; - const int klass_offset = oopDesc::klass_offset_in_bytes(); - const int holder_klass_offset = CompiledICHolder::holder_klass_offset(); - const int holder_method_offset = CompiledICHolder::holder_method_offset(); + const int klass_offset = oopDesc::klass_offset_in_bytes(); + const int holder_klass_offset = CompiledICHolder::holder_klass_offset(); + const int holder_metadata_offset = CompiledICHolder::holder_metadata_offset(); // Out-of-line call to ic_miss handler. __ call_ic_miss_handler(ic_miss, 0x11, 0, Z_R1_scratch); @@ -2659,7 +2659,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm // This def MUST MATCH code in gen_c2i_adapter! const Register code = Z_R11; - __ z_lg(Z_method, holder_method_offset, Z_method); + __ z_lg(Z_method, holder_metadata_offset, Z_method); __ load_and_test_long(Z_R0, method_(code)); __ z_brne(ic_miss); // Cache miss: call runtime to handle this. diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index e0065402b0..325f6dbcfe 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -2069,9 +2069,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, Register method_result, Register scan_temp, Register sethi_temp, - Label& L_no_such_interface) { + Label& L_no_such_interface, + bool return_method) { assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); - assert(itable_index.is_constant() || itable_index.as_register() == method_result, + assert(!return_method || itable_index.is_constant() || itable_index.as_register() == method_result, "caller must use same register for non-constant itable index as for method"); Label L_no_such_interface_restore; @@ -2103,11 +2104,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, add(scan_temp, itb_offset, scan_temp); add(recv_klass, scan_temp, scan_temp); - // Adjust recv_klass by scaled itable_index, so we can free itable_index. - RegisterOrConstant itable_offset = itable_index; - itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset); - itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset); - add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass); + if (return_method) { + // Adjust recv_klass by scaled itable_index, so we can free itable_index. + RegisterOrConstant itable_offset = itable_index; + itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset); + itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset); + add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass); + } // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { // if (scan->interface() == intf) { @@ -2142,12 +2145,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, bind(L_found_method); - // Got a hit. - int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); - // scan_temp[-scan_step] points to the vtable offset we need - ito_offset -= scan_step; - lduw(scan_temp, ito_offset, scan_temp); - ld_ptr(recv_klass, scan_temp, method_result); + if (return_method) { + // Got a hit. + int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); + // scan_temp[-scan_step] points to the vtable offset we need + ito_offset -= scan_step; + lduw(scan_temp, ito_offset, scan_temp); + ld_ptr(recv_klass, scan_temp, method_result); + } if (did_save) { Label L_done; diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index a401859e77..201abfc717 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -1290,7 +1290,8 @@ public: RegisterOrConstant itable_index, Register method_result, Register temp_reg, Register temp2_reg, - Label& no_such_interface); + Label& no_such_interface, + bool return_method = true); // virtual method calling void lookup_virtual_method(Register recv_klass, diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 613e662d65..4b8d40911b 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1079,7 +1079,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label ok, ok2; __ brx(Assembler::equal, false, Assembler::pt, ok); - __ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_method_offset(), G5_method); + __ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_metadata_offset(), G5_method); __ jump_to(ic_miss, G3_scratch); __ delayed()->nop(); diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index f828aa0e37..41cd9bb247 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -3173,15 +3173,15 @@ void TemplateTable::invokeinterface(int byte_no) { assert(byte_no == f1_byte, "use this argument"); const Register Rinterface = G1_scratch; + const Register Rmethod = Lscratch; const Register Rret = G3_scratch; - const Register Rindex = Lscratch; const Register O0_recv = O0; const Register O1_flags = O1; const Register O2_Klass = O2; const Register Rscratch = G4_scratch; assert_different_registers(Rscratch, G5_method); - prepare_invoke(byte_no, Rinterface, Rret, Rindex, O0_recv, O1_flags); + prepare_invoke(byte_no, Rinterface, Rret, Rmethod, O0_recv, O1_flags); // get receiver klass __ null_check(O0_recv, oopDesc::klass_offset_in_bytes()); @@ -3201,55 +3201,40 @@ void TemplateTable::invokeinterface(int byte_no) { __ bind(notMethod); + Register Rtemp = O1_flags; + + Label L_no_such_interface; + + // Receiver subtype check against REFC. + __ lookup_interface_method(// inputs: rec. class, interface, itable index + O2_Klass, Rinterface, noreg, + // outputs: temp reg1, temp reg2, temp reg3 + G5_method, Rscratch, Rtemp, + L_no_such_interface, + /*return_method=*/false); + __ profile_virtual_call(O2_Klass, O4); // // find entry point to call // - // compute start of first itableOffsetEntry (which is at end of vtable) - const int base = in_bytes(Klass::vtable_start_offset()); - Label search; - Register Rtemp = O1_flags; + // Get declaring interface class from method + __ ld_ptr(Rmethod, Method::const_offset(), Rinterface); + __ ld_ptr(Rinterface, ConstMethod::constants_offset(), Rinterface); + __ ld_ptr(Rinterface, ConstantPool::pool_holder_offset_in_bytes(), Rinterface); - __ ld(O2_Klass, in_bytes(Klass::vtable_length_offset()), Rtemp); - __ sll(Rtemp, LogBytesPerWord, Rtemp); // Rscratch *= 4; - if (Assembler::is_simm13(base)) { - __ add(Rtemp, base, Rtemp); - } else { - __ set(base, Rscratch); - __ add(Rscratch, Rtemp, Rtemp); - } - __ add(O2_Klass, Rtemp, Rscratch); + // Get itable index from method + const Register Rindex = G5_method; + __ ld(Rmethod, Method::itable_index_offset(), Rindex); + __ sub(Rindex, Method::itable_index_max, Rindex); + __ neg(Rindex); - __ bind(search); - - __ ld_ptr(Rscratch, itableOffsetEntry::interface_offset_in_bytes(), Rtemp); - { - Label ok; - - // Check that entry is non-null. Null entries are probably a bytecode - // problem. If the interface isn't implemented by the receiver class, - // the VM should throw IncompatibleClassChangeError. linkResolver checks - // this too but that's only if the entry isn't already resolved, so we - // need to check again. - __ br_notnull_short( Rtemp, Assembler::pt, ok); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); - __ should_not_reach_here(); - __ bind(ok); - } - - __ cmp(Rinterface, Rtemp); - __ brx(Assembler::notEqual, true, Assembler::pn, search); - __ delayed()->add(Rscratch, itableOffsetEntry::size() * wordSize, Rscratch); - - // entry found and Rscratch points to it - __ ld(Rscratch, itableOffsetEntry::offset_offset_in_bytes(), Rscratch); - - assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust instruction below"); - __ sll(Rindex, exact_log2(itableMethodEntry::size() * wordSize), Rindex); // Rindex *= 8; - __ add(Rscratch, Rindex, Rscratch); - __ ld_ptr(O2_Klass, Rscratch, G5_method); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + O2_Klass, Rinterface, Rindex, + // outputs: method, scan temp reg, temp reg + G5_method, Rscratch, Rtemp, + L_no_such_interface); // Check for abstract method error. { @@ -3266,6 +3251,10 @@ void TemplateTable::invokeinterface(int byte_no) { __ profile_arguments_type(G5_method, Rcall, Gargs, true); __ profile_called_method(G5_method, Rscratch); __ call_from_interpreter(Rcall, Gargs, Rret); + + __ bind(L_no_such_interface); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + __ should_not_reach_here(); } void TemplateTable::invokehandle(int byte_no) { diff --git a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp index 9e825aaa79..3f5a928f4a 100644 --- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp @@ -27,6 +27,7 @@ #include "code/vtableStubs.hpp" #include "interp_masm_sparc.hpp" #include "memory/resourceArea.hpp" +#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -140,7 +141,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { MacroAssembler* masm = new MacroAssembler(&cb); Register G3_Klass = G3_scratch; - Register G5_interface = G5; // Passed in as an argument + Register G5_icholder = G5; // Passed in as an argument + Register G4_interface = G4_scratch; Label search; // Entry arguments: @@ -164,14 +166,26 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { } #endif /* PRODUCT */ - Label throw_icce; + Label L_no_such_interface; Register L5_method = L5; + + // Receiver subtype check against REFC. + __ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface); __ lookup_interface_method(// inputs: rec. class, interface, itable index - G3_Klass, G5_interface, itable_index, + G3_Klass, G4_interface, itable_index, + // outputs: scan temp. reg1, scan temp. reg2 + L5_method, L2, L3, + L_no_such_interface, + /*return_method=*/ false); + + // Get Method* and entrypoint for compiler + __ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + G3_Klass, G4_interface, itable_index, // outputs: method, scan temp. reg L5_method, L2, L3, - throw_icce); + L_no_such_interface); #ifndef PRODUCT if (DebugVtables) { @@ -197,7 +211,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ JMP(G3_scratch, 0); __ delayed()->nop(); - __ bind(throw_icce); + __ bind(L_no_such_interface); AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); __ jump_to(icce, G3_scratch); __ delayed()->restore(); @@ -232,7 +246,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { MacroAssembler::instr_size_for_decode_klass_not_null() : 0); return basic + slop; } else { - const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + + const int basic = (48 LP64_ONLY(+ 6)) * BytesPerInstWord + // shift;add for load_klass (only shift with zero heap based) (UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 6b7f947de6..1be4263228 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -5733,8 +5733,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, RegisterOrConstant itable_index, Register method_result, Register scan_temp, - Label& L_no_such_interface) { - assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); + Label& L_no_such_interface, + bool return_method) { + assert_different_registers(recv_klass, intf_klass, scan_temp); + assert_different_registers(method_result, intf_klass, scan_temp); + assert(recv_klass != method_result || !return_method, + "recv_klass can be destroyed when method isn't needed"); + assert(itable_index.is_constant() || itable_index.as_register() == method_result, "caller must use same register for non-constant itable index as for method"); @@ -5751,9 +5756,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, // %%% Could store the aligned, prescaled offset in the klassoop. lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base)); - // Adjust recv_klass by scaled itable_index, so we can free itable_index. - assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); - lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off)); + if (return_method) { + // Adjust recv_klass by scaled itable_index, so we can free itable_index. + assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); + lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off)); + } // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { // if (scan->interface() == intf) { @@ -5787,9 +5794,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, bind(found_method); - // Got a hit. - movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); - movptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); + if (return_method) { + // Got a hit. + movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); + movptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); + } } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 2c2b17c06a..07ee112625 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -538,7 +538,8 @@ class MacroAssembler: public Assembler { RegisterOrConstant itable_index, Register method_result, Register scan_temp, - Label& no_such_interface); + Label& no_such_interface, + bool return_method = true); // virtual method calling void lookup_virtual_method(Register recv_klass, diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 47b9fe5c62..5034b4df94 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -952,7 +952,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label missed; __ movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset())); + __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset())); __ jcc(Assembler::notEqual, missed); // Method might have been compiled since the call site was patched to // interpreted if that is the case treat it as a miss so we can get diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index d81e965d05..fe56280ba6 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -942,7 +942,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm { __ load_klass(temp, receiver); __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset())); + __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset())); __ jcc(Assembler::equal, ok); __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp index 3d2f57f37b..421bfb38ea 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp @@ -3695,11 +3695,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) { void TemplateTable::invokeinterface(int byte_no) { transition(vtos, vtos); assert(byte_no == f1_byte, "use this argument"); - prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 itable index + prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method* rcx, rdx); // recv, flags - // rax: interface klass (from f1) - // rbx: itable index (from f2) + // rax: reference klass (from f1) + // rbx: method (from f2) // rcx: receiver // rdx: flags @@ -3721,10 +3721,28 @@ void TemplateTable::invokeinterface(int byte_no) { __ null_check(rcx, oopDesc::klass_offset_in_bytes()); __ load_klass(rdx, rcx); + Label no_such_interface, no_such_method; + + // Receiver subtype check against REFC. + // Superklass in rax. Subklass in rdx. Blows rcx, rdi. + __ lookup_interface_method(// inputs: rec. class, interface, itable index + rdx, rax, noreg, + // outputs: scan temp. reg, scan temp. reg + rbcp, rlocals, + no_such_interface, + /*return_method=*/false); + // profile this call + __ restore_bcp(); // rbcp was destroyed by receiver type check __ profile_virtual_call(rdx, rbcp, rlocals); - Label no_such_interface, no_such_method; + // Get declaring interface class from method, and itable index + __ movptr(rax, Address(rbx, Method::const_offset())); + __ movptr(rax, Address(rax, ConstMethod::constants_offset())); + __ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes())); + __ movl(rbx, Address(rbx, Method::itable_index_offset())); + __ subl(rbx, Method::itable_index_max); + __ negl(rbx); __ lookup_interface_method(// inputs: rec. class, interface, itable index rdx, rax, rbx, diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp index 3a5c7d0f38..8de43afb37 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp @@ -27,6 +27,7 @@ #include "code/vtableStubs.hpp" #include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" +#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -147,7 +148,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { MacroAssembler* masm = new MacroAssembler(&cb); // Entry arguments: - // rax,: Interface + // rax: CompiledICHolder // rcx: Receiver #ifndef PRODUCT @@ -155,25 +156,42 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); } #endif /* PRODUCT */ - // get receiver (need to skip return address on top of stack) - - assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); - - // get receiver klass (also an implicit null-check) - address npe_addr = __ pc(); - __ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes())); // Most registers are in use; we'll use rax, rbx, rsi, rdi // (If we need to make rsi, rdi callee-save, do a push/pop here.) - const Register method = rbx; - Label throw_icce; + const Register recv_klass_reg = rsi; + const Register holder_klass_reg = rax; // declaring interface klass (DECC) + const Register resolved_klass_reg = rbx; // resolved interface klass (REFC) + const Register temp_reg = rdi; - // Get Method* and entrypoint for compiler + const Register icholder_reg = rax; + __ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); + __ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + + Label L_no_such_interface; + + // get receiver klass (also an implicit null-check) + address npe_addr = __ pc(); + assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); + __ load_klass(recv_klass_reg, rcx); + + // Receiver subtype check against REFC. + // Destroys recv_klass_reg value. + __ lookup_interface_method(// inputs: rec. class, interface + recv_klass_reg, resolved_klass_reg, noreg, + // outputs: scan temp. reg1, scan temp. reg2 + recv_klass_reg, temp_reg, + L_no_such_interface, + /*return_method=*/false); + + // Get selected method from declaring class and itable index + const Register method = rbx; + __ load_klass(recv_klass_reg, rcx); // restore recv_klass_reg __ lookup_interface_method(// inputs: rec. class, interface, itable index - rsi, rax, itable_index, + recv_klass_reg, holder_klass_reg, itable_index, // outputs: method, scan temp. reg - method, rdi, - throw_icce); + method, temp_reg, + L_no_such_interface); // method (rbx): Method* // rcx: receiver @@ -193,9 +211,10 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { address ame_addr = __ pc(); __ jmp(Address(method, Method::from_compiled_offset())); - __ bind(throw_icce); + __ bind(L_no_such_interface); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); - masm->flush(); + + __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", @@ -220,7 +239,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); } else { // Itable stub size - return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0); + return (DebugVtables ? 256 : 110) + (CountCompiledCalls ? 6 : 0); } // In order to tune these parameters, run the JVM with VM options // +PrintMiscellaneous and +WizardMode to see information about diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp index 6c0a2fcb6a..f17330d26e 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -27,6 +27,7 @@ #include "code/vtableStubs.hpp" #include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" +#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -147,36 +148,50 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { #endif // Entry arguments: - // rax: Interface + // rax: CompiledICHolder // j_rarg0: Receiver - // Free registers (non-args) are rax (interface), rbx - - // get receiver (need to skip return address on top of stack) - - assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); - // get receiver klass (also an implicit null-check) - address npe_addr = __ pc(); - // Most registers are in use; we'll use rax, rbx, r10, r11 // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) - __ load_klass(r10, j_rarg0); + const Register recv_klass_reg = r10; + const Register holder_klass_reg = rax; // declaring interface klass (DECC) + const Register resolved_klass_reg = rbx; // resolved interface klass (REFC) + const Register temp_reg = r11; + + Label L_no_such_interface; + + const Register icholder_reg = rax; + __ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); + __ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + + // get receiver klass (also an implicit null-check) + assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); + address npe_addr = __ pc(); + __ load_klass(recv_klass_reg, j_rarg0); + + // Receiver subtype check against REFC. + // Destroys recv_klass_reg value. + __ lookup_interface_method(// inputs: rec. class, interface + recv_klass_reg, resolved_klass_reg, noreg, + // outputs: scan temp. reg1, scan temp. reg2 + recv_klass_reg, temp_reg, + L_no_such_interface, + /*return_method=*/false); + + // Get selected method from declaring class and itable index + const Register method = rbx; + __ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg + __ lookup_interface_method(// inputs: rec. class, interface, itable index + recv_klass_reg, holder_klass_reg, itable_index, + // outputs: method, scan temp. reg + method, temp_reg, + L_no_such_interface); // If we take a trap while this arg is on the stack we will not // be able to walk the stack properly. This is not an issue except // when there are mistakes in this assembly code that could generate // a spurious fault. Ask me how I know... - const Register method = rbx; - Label throw_icce; - - // Get Method* and entrypoint for compiler - __ lookup_interface_method(// inputs: rec. class, interface, itable index - r10, rax, itable_index, - // outputs: method, scan temp. reg - method, r11, - throw_icce); - // method (rbx): Method* // j_rarg0: receiver @@ -197,7 +212,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { address ame_addr = __ pc(); __ jmp(Address(method, Method::from_compiled_offset())); - __ bind(throw_icce); + __ bind(L_no_such_interface); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); @@ -224,8 +239,8 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { (UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); } else { // Itable stub size - return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) + - (UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); + return (DebugVtables ? 512 : 140) + (CountCompiledCalls ? 13 : 0) + + (UseCompressedClassPointers ? 2 * MacroAssembler::instr_size_for_decode_klass_not_null() : 0); } // In order to tune these parameters, run the JVM with VM options // +PrintMiscellaneous and +WizardMode to see information about diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java index 249430ad28..73b325952d 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java @@ -40,10 +40,10 @@ public class CompiledICHolder extends VMObject { } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("CompiledICHolder"); - holderMethod = new MetadataField(type.getAddressField("_holder_method"), 0); - holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0); - headerSize = type.getSize(); + Type type = db.lookupType("CompiledICHolder"); + holderMetadata = new MetadataField(type.getAddressField("_holder_metadata"), 0); + holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0); + headerSize = type.getSize(); } public CompiledICHolder(Address addr) { @@ -55,12 +55,12 @@ public class CompiledICHolder extends VMObject { private static long headerSize; // Fields - private static MetadataField holderMethod; + private static MetadataField holderMetadata; private static MetadataField holderKlass; // Accessors for declared fields - public Method getHolderMethod() { return (Method) holderMethod.getValue(this); } - public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); } + public Metadata getHolderMetadata() { return (Metadata) holderMetadata.getValue(this); } + public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); } public void printValueOn(PrintStream tty) { tty.print("CompiledICHolder"); diff --git a/hotspot/src/share/vm/aot/aotCompiledMethod.cpp b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp index c501ce12e6..ff8540ca8c 100644 --- a/hotspot/src/share/vm/aot/aotCompiledMethod.cpp +++ b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp @@ -273,7 +273,7 @@ void AOTCompiledMethod::metadata_do(void f(Metadata*)) { CompiledIC *ic = CompiledIC_at(&iter); if (ic->is_icholder_call()) { CompiledICHolder* cichk = ic->cached_icholder(); - f(cichk->holder_method()); + f(cichk->holder_metadata()); f(cichk->holder_klass()); } else { // Get Klass* or NULL (if value is -1) from GOT cell of virtual call PLT stub. diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index 97db8a54b6..0934e4803d 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -230,10 +230,13 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod #ifdef ASSERT int index = call_info->resolved_method()->itable_index(); assert(index == itable_index, "CallInfo pre-computes this"); -#endif //ASSERT InstanceKlass* k = call_info->resolved_method()->method_holder(); assert(k->verify_itable_index(itable_index), "sanity check"); - InlineCacheBuffer::create_transition_stub(this, k, entry); +#endif //ASSERT + CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(), + call_info->resolved_klass()()); + holder->claim(); + InlineCacheBuffer::create_transition_stub(this, holder, entry); } else { assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable"); // Can be different than selected_method->vtable_index(), due to package-private etc. @@ -517,7 +520,14 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method, bool CompiledIC::is_icholder_entry(address entry) { CodeBlob* cb = CodeCache::find_blob_unsafe(entry); - return (cb != NULL && cb->is_adapter_blob()); + if (cb != NULL && cb->is_adapter_blob()) { + return true; + } + // itable stubs also use CompiledICHolder + if (VtableStubs::is_entry_point(entry) && VtableStubs::stub_containing(entry)->is_itable_stub()) { + return true; + } + return false; } bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm) { diff --git a/hotspot/src/share/vm/code/compiledIC.hpp b/hotspot/src/share/vm/code/compiledIC.hpp index 15af2b44b8..dd8a7130f0 100644 --- a/hotspot/src/share/vm/code/compiledIC.hpp +++ b/hotspot/src/share/vm/code/compiledIC.hpp @@ -45,11 +45,11 @@ // \ / \ / // [4] \ / [4] \->-/ // \->- Megamorphic -<-/ -// (Method*) +// (CompiledICHolder*) // -// The text in paranteses () refere to the value of the inline cache receiver (mov instruction) +// The text in parentheses () refers to the value of the inline cache receiver (mov instruction) // -// The numbers in square brackets refere to the kind of transition: +// The numbers in square brackets refer to the kind of transition: // [1]: Initial fixup. Receiver it found from debug information // [2]: Compilation of a method // [3]: Recompilation of a method (note: only entry is changed. The Klass* must stay the same) diff --git a/hotspot/src/share/vm/code/compiledMethod.cpp b/hotspot/src/share/vm/code/compiledMethod.cpp index 30120b2989..0447c2bdc3 100644 --- a/hotspot/src/share/vm/code/compiledMethod.cpp +++ b/hotspot/src/share/vm/code/compiledMethod.cpp @@ -417,8 +417,7 @@ void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClos // yet be marked below. (We check this further below). CompiledICHolder* cichk_oop = ic->cached_icholder(); - if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) && - cichk_oop->holder_klass()->is_loader_alive(is_alive)) { + if (cichk_oop->is_loader_alive(is_alive)) { return; } } else { diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index f82872baf1..80b894df8f 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1577,7 +1577,7 @@ void nmethod::metadata_do(void f(Metadata*)) { CompiledIC *ic = CompiledIC_at(&iter); if (ic->is_icholder_call()) { CompiledICHolder* cichk = ic->cached_icholder(); - f(cichk->holder_method()); + f(cichk->holder_metadata()); f(cichk->holder_klass()); } else { Metadata* ic_oop = ic->cached_metadata(); diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index d053786f03..06052f9ab8 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -795,7 +795,7 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte // it is not an interface. The receiver for invokespecial calls within interface // methods must be checked for every call. InstanceKlass* sender = pool->pool_holder(); - sender = sender->is_anonymous() ? sender->host_klass() : sender; + sender = sender->has_host_klass() ? sender->host_klass() : sender; switch (info.call_kind()) { case CallInfo::direct_call: @@ -813,6 +813,7 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte case CallInfo::itable_call: cp_cache_entry->set_itable_call( bytecode, + info.resolved_klass(), info.resolved_method(), info.itable_index()); break; diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index d7ae64effe..2d323cd7d3 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1061,11 +1061,7 @@ void LinkResolver::resolve_special_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK); - runtime_resolve_special_method(result, resolved_method, - link_info.resolved_klass(), - link_info.current_klass(), - recv, - link_info.check_access(), CHECK); + runtime_resolve_special_method(result, link_info, resolved_method, recv, CHECK); } // throws linktime exceptions @@ -1148,11 +1144,11 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_ // throws runtime exceptions void LinkResolver::runtime_resolve_special_method(CallInfo& result, + const LinkInfo& link_info, const methodHandle& resolved_method, - KlassHandle resolved_klass, - KlassHandle current_klass, - Handle recv, - bool check_access, TRAPS) { + Handle recv, TRAPS) { + + KlassHandle resolved_klass = link_info.resolved_klass(); // resolved method is selected method unless we have an old-style lookup // for a superclass method @@ -1160,12 +1156,13 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, // no checks for shadowing methodHandle sel_method(THREAD, resolved_method()); - if (check_access && + if (link_info.check_access() && // check if the method is not resolved_method->name() != vmSymbols::object_initializer_name()) { - // check if this is an old-style super call and do a new lookup if so + // check if this is an old-style super call and do a new lookup if so // a) check if ACC_SUPER flag is set for the current class + KlassHandle current_klass = link_info.current_klass(); if ((current_klass->is_super() || !AllowNonVirtualCalls) && // b) check if the class of the resolved_klass is a superclass // (not supertype in order to exclude interface classes) of the current class. @@ -1185,6 +1182,9 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, Method::name_and_sig_as_C_string(resolved_klass(), resolved_method->name(), resolved_method->signature())); + // check loader constraints if found a different method + } else if (sel_method() != resolved_method()) { + check_method_loader_constraints(link_info, sel_method, "method", CHECK); } } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 2f14496bb0..7192b8c133 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,11 +227,10 @@ class LinkResolver: AllStatic { static methodHandle linktime_resolve_interface_method (const LinkInfo& link_info, TRAPS); static void runtime_resolve_special_method (CallInfo& result, + const LinkInfo& link_info, const methodHandle& resolved_method, - KlassHandle resolved_klass, - KlassHandle current_klass, - Handle recv, - bool check_access, TRAPS); + Handle recv, TRAPS); + static void runtime_resolve_virtual_method (CallInfo& result, const methodHandle& resolved_method, KlassHandle resolved_klass, diff --git a/hotspot/src/share/vm/oops/compiledICHolder.cpp b/hotspot/src/share/vm/oops/compiledICHolder.cpp index 55397d06c1..19f44adab8 100644 --- a/hotspot/src/share/vm/oops/compiledICHolder.cpp +++ b/hotspot/src/share/vm/oops/compiledICHolder.cpp @@ -32,8 +32,8 @@ volatile int CompiledICHolder::_live_count; volatile int CompiledICHolder::_live_not_claimed_count; -CompiledICHolder::CompiledICHolder(Method* method, Klass* klass) - : _holder_method(method), _holder_klass(klass) { +CompiledICHolder::CompiledICHolder(Metadata* metadata, Klass* klass) + : _holder_metadata(metadata), _holder_klass(klass) { #ifdef ASSERT Atomic::inc(&_live_count); Atomic::inc(&_live_not_claimed_count); @@ -47,12 +47,28 @@ CompiledICHolder::~CompiledICHolder() { } #endif // ASSERT +bool CompiledICHolder::is_loader_alive(BoolObjectClosure* is_alive) { + if (_holder_metadata->is_method()) { + if (!((Method*)_holder_metadata)->method_holder()->is_loader_alive(is_alive)) { + return false; + } + } else if (_holder_metadata->is_klass()) { + if (!((Klass*)_holder_metadata)->is_loader_alive(is_alive)) { + return false; + } + } + if (!_holder_klass->is_loader_alive(is_alive)) { + return false; + } + return true; +} + // Printing void CompiledICHolder::print_on(outputStream* st) const { st->print("%s", internal_name()); - st->print(" - method: "); holder_method()->print_value_on(st); st->cr(); - st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr(); + st->print(" - metadata: "); holder_metadata()->print_value_on(st); st->cr(); + st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr(); } void CompiledICHolder::print_value_on(outputStream* st) const { @@ -63,7 +79,7 @@ void CompiledICHolder::print_value_on(outputStream* st) const { // Verification void CompiledICHolder::verify_on(outputStream* st) { - guarantee(holder_method()->is_method(), "should be method"); + guarantee(holder_metadata()->is_method() || holder_metadata()->is_klass(), "should be method or klass"); guarantee(holder_klass()->is_klass(), "should be klass"); } diff --git a/hotspot/src/share/vm/oops/compiledICHolder.hpp b/hotspot/src/share/vm/oops/compiledICHolder.hpp index c3e899fde8..af4a38a9f3 100644 --- a/hotspot/src/share/vm/oops/compiledICHolder.hpp +++ b/hotspot/src/share/vm/oops/compiledICHolder.hpp @@ -29,8 +29,9 @@ #include "utilities/macros.hpp" // A CompiledICHolder* is a helper object for the inline cache implementation. -// It holds an intermediate value (method+klass pair) used when converting from -// compiled to an interpreted call. +// It holds: +// (1) (method+klass pair) when converting from compiled to an interpreted call +// (2) (klass+klass pair) when calling itable stub from megamorphic compiled call // // These are always allocated in the C heap and are freed during a // safepoint by the ICBuffer logic. It's unsafe to free them earlier @@ -45,32 +46,33 @@ class CompiledICHolder : public CHeapObj { static volatile int _live_not_claimed_count; // allocated but not yet in use so not // reachable by iterating over nmethods - Method* _holder_method; + Metadata* _holder_metadata; Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass CompiledICHolder* _next; public: // Constructor - CompiledICHolder(Method* method, Klass* klass); + CompiledICHolder(Metadata* metadata, Klass* klass); ~CompiledICHolder() NOT_DEBUG_RETURN; static int live_count() { return _live_count; } static int live_not_claimed_count() { return _live_not_claimed_count; } // accessors - Method* holder_method() const { return _holder_method; } Klass* holder_klass() const { return _holder_klass; } + Metadata* holder_metadata() const { return _holder_metadata; } - void set_holder_method(Method* m) { _holder_method = m; } - void set_holder_klass(Klass* k) { _holder_klass = k; } + void set_holder_metadata(Metadata* m) { _holder_metadata = m; } + void set_holder_klass(Klass* k) { _holder_klass = k; } - // interpreter support (offsets in bytes) - static int holder_method_offset() { return offset_of(CompiledICHolder, _holder_method); } + static int holder_metadata_offset() { return offset_of(CompiledICHolder, _holder_metadata); } static int holder_klass_offset() { return offset_of(CompiledICHolder, _holder_klass); } CompiledICHolder* next() { return _next; } void set_next(CompiledICHolder* n) { _next = n; } + bool is_loader_alive(BoolObjectClosure* is_alive); + // Verify void verify_on(outputStream* st); diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 86cfa19217..173108fd09 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -958,7 +958,7 @@ class SymbolHashMap: public CHeapObj { delete(cur); } } - delete _buckets; + FREE_C_HEAP_ARRAY(SymbolHashMapBucket, _buckets); } }; // End SymbolHashMap class diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index b7522433bb..9ba540097e 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -255,14 +255,16 @@ void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, method set_direct_or_vtable_call(invoke_code, method, index, false); } -void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, const methodHandle& method, int index) { +void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, + KlassHandle referenced_klass, + const methodHandle& method, int index) { assert(method->method_holder()->verify_itable_index(index), ""); assert(invoke_code == Bytecodes::_invokeinterface, ""); InstanceKlass* interf = method->method_holder(); assert(interf->is_interface(), "must be an interface"); assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here"); - set_f1(interf); - set_f2(index); + set_f1(referenced_klass()); + set_f2((intx)method()); set_method_flags(as_TosState(method->result_type()), 0, // no option bits method()->size_of_parameters()); @@ -434,10 +436,23 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(const constantPoolHandle& cp #if INCLUDE_JVMTI + +void log_adjust(const char* entry_type, Method* old_method, Method* new_method, bool* trace_name_printed) { + if (log_is_enabled(Info, redefine, class, update)) { + ResourceMark rm; + if (!(*trace_name_printed)) { + log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); + *trace_name_printed = true; + } + log_debug(redefine, class, update, constantpool) + ("cpc %s entry update: %s(%s)", entry_type, new_method->name()->as_C_string(), new_method->signature()->as_C_string()); + } +} + // RedefineClasses() API support: // If this ConstantPoolCacheEntry refers to old_method then update it // to refer to new_method. -bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, +void ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, Method* new_method, bool * trace_name_printed) { if (is_vfinal()) { @@ -446,63 +461,35 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, // match old_method so need an update // NOTE: can't use set_f2_as_vfinal_method as it asserts on different values _f2 = (intptr_t)new_method; - if (log_is_enabled(Info, redefine, class, update)) { - ResourceMark rm; - if (!(*trace_name_printed)) { - log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); - *trace_name_printed = true; - } - log_debug(redefine, class, update, constantpool) - ("cpc vf-entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string()); - } - return true; + log_adjust("vfinal", old_method, new_method, trace_name_printed); } - - // f1() is not used with virtual entries so bail out - return false; + return; } - if (_f1 == NULL) { - // NULL f1() means this is a virtual entry so bail out - // We are assuming that the vtable index does not need change. - return false; - } + assert (_f1 != NULL, "should not call with uninteresting entry"); - if (_f1 == old_method) { + if (!(_f1->is_method())) { + // _f1 is a Klass* for an interface, _f2 is the method + if (f2_as_interface_method() == old_method) { + _f2 = (intptr_t)new_method; + log_adjust("interface", old_method, new_method, trace_name_printed); + } + } else if (_f1 == old_method) { _f1 = new_method; - if (log_is_enabled(Info, redefine, class, update)) { - ResourceMark rm; - if (!(*trace_name_printed)) { - log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); - *trace_name_printed = true; - } - log_debug(redefine, class, update, constantpool) - ("cpc entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string()); - } - return true; + log_adjust("special, static or dynamic", old_method, new_method, trace_name_printed); } - - return false; } // a constant pool cache entry should never contain old or obsolete methods bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() { - if (is_vfinal()) { - // virtual and final so _f2 contains method ptr instead of vtable index - Metadata* f2 = (Metadata*)_f2; - // Return false if _f2 refers to an old or an obsolete method. - // _f2 == NULL || !_f2->is_method() are just as unexpected here. - return (f2 != NULL NOT_PRODUCT(&& f2->is_valid()) && f2->is_method() && - !((Method*)f2)->is_old() && !((Method*)f2)->is_obsolete()); - } else if (_f1 == NULL || - (NOT_PRODUCT(_f1->is_valid() &&) !_f1->is_method())) { - // _f1 == NULL || !_f1->is_method() are OK here + Method* m = get_interesting_method_entry(NULL); + // return false if m refers to a non-deleted old or obsolete method + if (m != NULL) { + assert(m->is_valid() && m->is_method(), "m is a valid method"); + return !m->is_old() && !m->is_obsolete(); // old is always set for old and obsolete + } else { return true; } - // return false if _f1 refers to a non-deleted old or obsolete method - return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() && - (f1_as_method()->is_deleted() || - (!f1_as_method()->is_old() && !f1_as_method()->is_obsolete()))); } Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { @@ -519,10 +506,11 @@ Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { return NULL; } else { if (!(_f1->is_method())) { - // _f1 can also contain a Klass* for an interface - return NULL; + // _f1 is a Klass* for an interface + m = f2_as_interface_method(); + } else { + m = f1_as_method(); } - m = f1_as_method(); } assert(m != NULL && m->is_method(), "sanity check"); if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) { diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp index 9db57ffa03..6b689314da 100644 --- a/hotspot/src/share/vm/oops/cpCache.hpp +++ b/hotspot/src/share/vm/oops/cpCache.hpp @@ -249,6 +249,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { void set_itable_call( Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface + KlassHandle referenced_klass, // the referenced klass in the InterfaceMethodref const methodHandle& method, // the resolved interface method int itable_index // index into itable for the method ); @@ -345,6 +346,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { bool is_f1_null() const { Metadata* f1 = f1_ord(); return f1 == NULL; } // classifies a CPC entry as unbound int f2_as_index() const { assert(!is_vfinal(), ""); return (int) _f2; } Method* f2_as_vfinal_method() const { assert(is_vfinal(), ""); return (Method*)_f2; } + Method* f2_as_interface_method() const { assert(bytecode_1() == Bytecodes::_invokeinterface, ""); return (Method*)_f2; } int field_index() const { assert(is_field_entry(), ""); return (_flags & field_index_mask); } int parameter_size() const { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); } bool is_volatile() const { return (_flags & (1 << is_volatile_shift)) != 0; } @@ -377,7 +379,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - bool adjust_method_entry(Method* old_method, Method* new_method, + void adjust_method_entry(Method* old_method, Method* new_method, bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); Method* get_interesting_method_entry(Klass* k); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 1756b9fc86..2ae6511016 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -625,9 +625,11 @@ class InstanceKlass: public Klass { InstanceKlass* host_klass() const { InstanceKlass** hk = adr_host_klass(); if (hk == NULL) { + assert(!is_anonymous(), "Anonymous classes have host klasses"); return NULL; } else { assert(*hk != NULL, "host klass should always be set if the address is not null"); + assert(is_anonymous(), "Only anonymous classes have host klasses"); return *hk; } } @@ -639,6 +641,9 @@ class InstanceKlass: public Klass { *addr = host; } } + bool has_host_klass() const { + return adr_host_klass() != NULL; + } bool is_anonymous() const { return (_misc_flags & _misc_is_anonymous) != 0; } diff --git a/hotspot/src/share/vm/oops/klassVtable.cpp b/hotspot/src/share/vm/oops/klassVtable.cpp index 9715d2b087..0943d52b50 100644 --- a/hotspot/src/share/vm/oops/klassVtable.cpp +++ b/hotspot/src/share/vm/oops/klassVtable.cpp @@ -1173,7 +1173,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass Array* methods = InstanceKlass::cast(interf_h())->methods(); int nof_methods = methods->length(); HandleMark hm; - assert(nof_methods > 0, "at least one method must exist for interface to be in vtable"); Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader()); int ime_count = method_count_for_interface(interf_h()); @@ -1350,8 +1349,10 @@ void visit_all_interfaces(Array* transitive_intf, InterfaceVisiterClosur } } - // Only count interfaces with at least one method - if (method_count > 0) { + // Visit all interfaces which either have any methods or can participate in receiver type check. + // We do not bother to count methods in transitive interfaces, although that would allow us to skip + // this step in the rare case of a zero-method interface extending another zero-method interface. + if (method_count > 0 || InstanceKlass::cast(intf)->transitive_interfaces()->length() > 0) { blk->doit(intf, method_count); } } diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 6675410db8..a1f8e66e72 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -700,6 +700,7 @@ class Method : public Metadata { static ByteSize from_interpreted_offset() { return byte_offset_of(Method, _from_interpreted_entry ); } static ByteSize interpreter_entry_offset() { return byte_offset_of(Method, _i2i_entry ); } static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } + static ByteSize itable_index_offset() { return byte_offset_of(Method, _vtable_index ); } // for code generation static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index acda443267..5f81a7ecb6 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -2839,7 +2839,7 @@ jni_Get##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, EntryProbe; \ DT_VOID_RETURN_MARK(Get##Result##ArrayRegion); \ typeArrayOop src = typeArrayOop(JNIHandles::resolve_non_null(array)); \ - if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)src->length())) { \ + if (start < 0 || len < 0 || (start > src->length() - len)) { \ THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \ } else { \ if (len > 0) { \ @@ -2889,7 +2889,7 @@ jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, EntryProbe; \ DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \ typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \ - if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)dst->length())) { \ + if (start < 0 || len < 0 || (start > dst->length() - len)) { \ THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \ } else { \ if (len > 0) { \ @@ -3126,7 +3126,7 @@ JNI_ENTRY(void, jni_GetStringRegion(JNIEnv *env, jstring string, jsize start, js DT_VOID_RETURN_MARK(GetStringRegion); oop s = JNIHandles::resolve_non_null(string); int s_len = java_lang_String::length(s); - if (start < 0 || len < 0 || start + len > s_len) { + if (start < 0 || len < 0 || start > s_len - len) { THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException()); } else { if (len > 0) { @@ -3152,7 +3152,7 @@ JNI_ENTRY(void, jni_GetStringUTFRegion(JNIEnv *env, jstring string, jsize start, DT_VOID_RETURN_MARK(GetStringUTFRegion); oop s = JNIHandles::resolve_non_null(string); int s_len = java_lang_String::length(s); - if (start < 0 || len < 0 || start + len > s_len) { + if (start < 0 || len < 0 || start > s_len - len) { THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException()); } else { //%note jni_7 diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index a945f4f4a0..79956edf1d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -230,7 +230,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(ArrayKlass, _dimension, int) \ volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \ volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \ - nonstatic_field(CompiledICHolder, _holder_method, Method*) \ + nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \ nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \ nonstatic_field(ConstantPool, _tags, Array*) \ nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \ diff --git a/hotspot/test/native/code/test_vtableStub.cpp b/hotspot/test/native/code/test_vtableStub.cpp new file mode 100644 index 0000000000..9930f95127 --- /dev/null +++ b/hotspot/test/native/code/test_vtableStub.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "code/vtableStubs.hpp" +#include "runtime/interfaceSupport.hpp" +#include "unittest.hpp" + +TEST_VM(code, vtableStubs) { + // Should be in VM to use locks + ThreadInVMfromNative ThreadInVMfromNative(JavaThread::current()); + + VtableStubs::find_vtable_stub(0); // min vtable index + for (int i = 0; i < 15; i++) { + VtableStubs::find_vtable_stub((1 << i) - 1); + VtableStubs::find_vtable_stub((1 << i)); + } + VtableStubs::find_vtable_stub((1 << 15) - 1); // max vtable index +} + +TEST_VM(code, itableStubs) { + // Should be in VM to use locks + ThreadInVMfromNative ThreadInVMfromNative(JavaThread::current()); + + VtableStubs::find_itable_stub(0); // min itable index + for (int i = 0; i < 15; i++) { + VtableStubs::find_itable_stub((1 << i) - 1); + VtableStubs::find_itable_stub((1 << i)); + } + VtableStubs::find_itable_stub((1 << 15) - 1); // max itable index +} diff --git a/hotspot/test/runtime/RedefineTests/RedefineInterfaceCall.java b/hotspot/test/runtime/RedefineTests/RedefineInterfaceCall.java new file mode 100644 index 0000000000..ec3efe7431 --- /dev/null +++ b/hotspot/test/runtime/RedefineTests/RedefineInterfaceCall.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174962 + * @summary Redefine class with interface method call + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.compiler + * java.instrument + * jdk.jartool/sun.tools.jar + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+update*=trace RedefineInterfaceCall + */ + +import static jdk.test.lib.Asserts.assertEquals; + +interface I1 { default int m() { return 0; } } +interface I2 extends I1 {} + +public class RedefineInterfaceCall { + + public static class C implements I2 { + public int test(I2 i) { + return i.m(); // invokeinterface cpCacheEntry + } + } + + static String newI1 = + "interface I1 { default int m() { return 1; } }"; + + static String newC = + "public class RedefineInterfaceCall$C implements I2 { " + + " public int test(I2 i) { " + + " return i.m(); " + + " } " + + "} "; + + static int test(I2 i) { + return i.m(); // invokeinterface cpCacheEntry + } + + public static void main(String[] args) throws Exception { + C c = new C(); + + assertEquals(test(c), 0); + assertEquals(c.test(c), 0); + + RedefineClassHelper.redefineClass(C.class, newC); + + assertEquals(c.test(c), 0); + + RedefineClassHelper.redefineClass(I1.class, newI1); + + assertEquals(test(c), 1); + assertEquals(c.test(c), 1); + + RedefineClassHelper.redefineClass(C.class, newC); + + assertEquals(c.test(c), 1); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java index 00e25bce83..38e9b75148 100644 --- a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java @@ -62,8 +62,8 @@ public class TransformTestCommon { String parent, String child) throws Exception { - String parentSharedMatch = parent + " source: shared objects file"; - String childSharedMatch = child + " source: shared objects file"; + String parentSharedMatch = " " + parent + " source: shared objects file"; + String childSharedMatch = " " + child + " source: shared objects file"; if (entry.isParentExpectedShared) out.shouldContain(parentSharedMatch); diff --git a/make/SourceRevision.gmk b/make/SourceRevision.gmk index a14b3ef0e2..2218b21c37 100644 --- a/make/SourceRevision.gmk +++ b/make/SourceRevision.gmk @@ -39,8 +39,6 @@ include MakeBase.gmk # revisions of all repos will be stored in a file in the top dir, which is then # used when creating the tracker file. -STORED_SOURCE_REVISION := $(TOPDIR)/.src-rev - # Are we using mercurial? ifneq ($(and $(HG), $(wildcard $(TOPDIR)/.hg)), ) @@ -108,7 +106,15 @@ else $(call LogInfo, No mercurial configuration present$(COMMA) not updating .src-rev) $(SOURCE_REVISION_TRACKER): $(STORED_SOURCE_REVISION) - $(install-file) + $(call MakeDir, $(@D)) + $(RM) $@ + # Only include revisions for repos that are included in the current + # source set. + for r in `cat $<`; do \ + if [ -d "$(TOPDIR)/`$(ECHO) $$r | $(CUT) -d':' -f1`" ]; then \ + $(PRINTF) "$$r " >> $@; \ + fi; \ + done create-source-revision-tracker: $(SOURCE_REVISION_TRACKER) else diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index ff8ced0fcf..6f7b31dea2 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -342,11 +342,25 @@ endif # HAS_FILE_FUNCTION # the build was created from SOURCE_REVISION_TRACKER := $(SUPPORT_OUTPUTDIR)/src-rev/source-revision-tracker -# Locate all hg repositories included in the forest, as absolute paths +# A cache of the mercurial information which can be dropped in the top of the +# source tree for inclusion in a source bundle. +STORED_SOURCE_REVISION := $(TOPDIR)/.src-rev + +# Locate all hg repositories included in the forest, as absolute paths. Use .hg +# dirs if present, otherwise parse the .src-rev file and match dirs. FindAllReposAbs = \ - $(strip $(sort $(dir $(filter-out $(SRC_ROOT)/build/%, $(wildcard \ - $(addprefix $(SRC_ROOT)/, .hg */.hg */*/.hg */*/*/.hg) \ - ))))) + $(if $(and $(HG), $(wildcard $(TOPDIR)/.hg)), \ + $(strip $(sort $(dir $(filter-out $(SRC_ROOT)/build/%, $(wildcard \ + $(addprefix $(SRC_ROOT)/, .hg */.hg */*/.hg */*/*/.hg)))))) \ + , \ + $(if $(wildcard $(STORED_SOURCE_REVISION)), \ + $(strip $(foreach r, $(call ReadFile, $(STORED_SOURCE_REVISION)), \ + $(wildcard $(TOPDIR)/$(firstword $(subst :,$(SPACE),$r))/) \ + )) \ + , \ + $(error No mercurial or .src-rev available, cannot list repositories) \ + ) \ + ) # Locate all hg repositories included in the forest, as relative paths FindAllReposRel = \