diff --git a/.hgtags b/.hgtags
index 39ca1fe7089..abf4dd939ca 100644
--- a/.hgtags
+++ b/.hgtags
@@ -374,3 +374,4 @@ d53037a90c441cb528dc41c30827985de0e67c62 jdk-9+123
e8373543a3f0f60589b7d72b1f9b172721124caf jdk-9+129
e613affb88d178dc7c589f1679db113d589bddb4 jdk-9+130
4d2a15091124488080d65848b704e25599b2aaeb jdk-9+131
+2e83d21d78cd9c1d52e6cd2599e9c8aa36ea1f52 jdk-9+132
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 9c7560ce460..2ab754ea198 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -374,3 +374,4 @@ b30ae794d974d7dd3eb4e84203f70021823fa6c6 jdk-9+128
f5902d3841b82cac6e7716a20c24e8e916fb14a8 jdk-9+129
d94d54a3192fea79234c3ac55cd0b4052d45e954 jdk-9+130
8728756c2f70a79a90188f4019cfd6b9a275765c jdk-9+131
+a24702d4d5ab0015a5c553ed57f66fce7d85155e jdk-9+132
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index e4d41e81b43..c591a79d327 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -251,8 +251,6 @@ SUPPORT_HEADLESS:=@SUPPORT_HEADLESS@
# Legacy support
USE_NEW_HOTSPOT_BUILD:=@USE_NEW_HOTSPOT_BUILD@
-MACOSX_UNIVERSAL=@MACOSX_UNIVERSAL@
-
# JDK_OUTPUTDIR specifies where a working jvm is built.
# You can run $(JDK_OUTPUTDIR)/bin/java
# Though the layout of the contents of $(JDK_OUTPUTDIR) is not
diff --git a/corba/.hgtags b/corba/.hgtags
index 1e46a9e1c46..2ba88ee0421 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -374,3 +374,4 @@ c7f5ba08fcd4b8416e62c21229f9a07c95498919 jdk-9+126
c3e83ccab3bb1733ae903d681879a33f85ed465c jdk-9+129
77f9692d5976ae155773dd3e07533616bb95bae1 jdk-9+130
f7e1d5337c2e550fe553df7a3886bbed80292ecd jdk-9+131
+1ab4b9399c4cba584f66c1c088188f2f565fbf9c jdk-9+132
diff --git a/corba/src/java.corba/share/classes/module-info.java b/corba/src/java.corba/share/classes/module-info.java
index 644e19c6f80..8c21cc30ca0 100644
--- a/corba/src/java.corba/share/classes/module-info.java
+++ b/corba/src/java.corba/share/classes/module-info.java
@@ -23,6 +23,9 @@
* questions.
*/
+/**
+ * Defines the Java binding of the OMG CORBA APIs, and the RMI-IIOP API.
+ */
module java.corba {
requires public java.desktop;
requires public java.rmi;
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index ada9a1ad431..dd85a0e3b2b 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -534,3 +534,4 @@ adc8c84b7cf8c540d920182f78a2bc982366432a jdk-9+126
e96b34b76d863ed1fa04e0eeb3f297ac17b490fd jdk-9+129
7d54c7056328b6a2bf4877458b8f4d8cd870f93b jdk-9+130
943bf73b49c33c2d7cbd796f6a4ae3c7a00ae932 jdk-9+131
+713951c08aa26813375175c2ab6cc99ff2a56903 jdk-9+132
diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml
index 3a06d2fc2b6..48b58c3f7c7 100644
--- a/hotspot/src/share/vm/prims/jvmti.xml
+++ b/hotspot/src/share/vm/prims/jvmti.xml
@@ -7152,15 +7152,19 @@ class C2 extends C1 implements I2 {
returns JNI_FALSE) the class can be neither
redefined nor retransformed.
- Primitive classes (for example, java.lang.Integer.TYPE)
- and array classes are never modifiable.
+ Primitive classes (for example, java.lang.Integer.TYPE),
+ array classes, and some implementation defined classes are never modifiable.
new
- If possessed then all classes (except primitive and array classes)
- are modifiable.
+ If possessed then all classes (except primitive, array, and some implementation defined
+ classes) are modifiable (redefine or retransform).
+
+
+ If possessed then all classes (except primitive, array, and some implementation defined
+ classes) are modifiable with .
No effect on the result of the function.
@@ -9900,7 +9904,7 @@ myInit() {
- Can modify (retransform or redefine) any non-primitive non-array class.
+ Can modify (retransform or redefine) any modifiable class.
See .
@@ -10024,7 +10028,8 @@ myInit() {
- can be called on any class
+ can be called on any modifiable class.
+ See .
(
must also be set)
@@ -12494,8 +12499,8 @@ myInit() {
Otherwise, this event may be sent before the VM is initialized (the start
phase).
Some classes might not be compatible
- with the function (eg. ROMized classes) and this event will not be
- generated for these classes.
+ with the function (eg. ROMized classes or implementation defined classes) and this event will
+ not be generated for these classes.
The agent must allocate the space for the modified
class file data buffer
@@ -14498,6 +14503,10 @@ typedef void (JNICALL *jvmtiEventVMInit)
- Add new capability can_generate_early_class_hook_events
- Add new function GetNamedModule
+
+ Clarified can_redefine_any_classes, can_retransform_any_classes and IsModifiableClass API to
+ disallow some implementation defined classes.
+
diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
index 5b44ee01085..f1c5f962b17 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
@@ -283,7 +283,7 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
return JVMTI_ERROR_INVALID_CLASS;
}
- if (java_lang_Class::is_primitive(k_mirror)) {
+ if (!VM_RedefineClasses::is_modifiable_class(k_mirror)) {
return JVMTI_ERROR_UNMODIFIABLE_CLASS;
}
@@ -294,9 +294,6 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
if (status & (JVMTI_CLASS_STATUS_ERROR)) {
return JVMTI_ERROR_INVALID_CLASS;
}
- if (status & (JVMTI_CLASS_STATUS_ARRAY)) {
- return JVMTI_ERROR_UNMODIFIABLE_CLASS;
- }
instanceKlassHandle ikh(current_thread, k_oop);
if (ikh->get_cached_class_file_bytes() == NULL) {
diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
index f173e570dce..8a84d0ecf23 100644
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
@@ -130,7 +130,7 @@ bool VM_RedefineClasses::doit_prologue() {
}
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
- // classes for primitives and arrays cannot be redefined
+ // classes for primitives and arrays and vm anonymous classes cannot be redefined
// check here so following code can assume these classes are InstanceKlass
if (!is_modifiable_class(mirror)) {
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
@@ -250,9 +250,14 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
if (java_lang_Class::is_primitive(klass_mirror)) {
return false;
}
- Klass* the_class_oop = java_lang_Class::as_Klass(klass_mirror);
+ Klass* k = java_lang_Class::as_Klass(klass_mirror);
// classes for arrays cannot be redefined
- if (the_class_oop == NULL || !the_class_oop->is_instance_klass()) {
+ if (k == NULL || !k->is_instance_klass()) {
+ return false;
+ }
+
+ // Cannot redefine or retransform an anonymous class.
+ if (InstanceKlass::cast(k)->is_anonymous()) {
return false;
}
return true;
diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp
index 12758ab02e4..c9c8c73a92c 100644
--- a/hotspot/src/share/vm/utilities/bitMap.cpp
+++ b/hotspot/src/share/vm/utilities/bitMap.cpp
@@ -376,77 +376,99 @@ void BitMap::par_at_put_large_range(idx_t beg, idx_t end, bool value) {
par_put_range_within_word(bit_index(end_full_word), end, value);
}
+inline bm_word_t tail_mask(idx_t tail_bits) {
+ assert(tail_bits != 0, "precondition"); // Works, but shouldn't be called.
+ assert(tail_bits < (idx_t)BitsPerWord, "precondition");
+ return (bm_word_t(1) << tail_bits) - 1;
+}
+
+// Get the low tail_bits of value, which is the last partial word of a map.
+inline bm_word_t tail_of_map(bm_word_t value, idx_t tail_bits) {
+ return value & tail_mask(tail_bits);
+}
+
+// Compute the new last word of a map with a non-aligned length.
+// new_value has the new trailing bits of the map in the low tail_bits.
+// old_value is the last word of the map, including bits beyond the end.
+// Returns old_value with the low tail_bits replaced by the corresponding
+// bits in new_value.
+inline bm_word_t merge_tail_of_map(bm_word_t new_value,
+ bm_word_t old_value,
+ idx_t tail_bits) {
+ bm_word_t mask = tail_mask(tail_bits);
+ return (new_value & mask) | (old_value & ~mask);
+}
+
bool BitMap::contains(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size_in_words(); index++) {
- bm_word_t word_union = dest_map[index] | other_map[index];
- // If this has more bits set than dest_map[index], then other is not a
- // subset.
- if (word_union != dest_map[index]) return false;
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ // false if other bitmap has bits set which are clear in this bitmap.
+ if ((~dest_map[index] & other_map[index]) != 0) return false;
}
- return true;
+ idx_t rest = bit_in_word(size());
+ // true unless there is a partial-word tail in which the other
+ // bitmap has bits set which are clear in this bitmap.
+ return (rest == 0) || tail_of_map(~dest_map[limit] & other_map[limit], rest) == 0;
}
bool BitMap::intersects(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size_in_words(); index++) {
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
if ((dest_map[index] & other_map[index]) != 0) return true;
}
- // Otherwise, no intersection.
- return false;
+ idx_t rest = bit_in_word(size());
+ // false unless there is a partial-word tail with non-empty intersection.
+ return (rest > 0) && tail_of_map(dest_map[limit] & other_map[limit], rest) != 0;
}
void BitMap::set_union(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size_in_words(); index++) {
- dest_map[index] = dest_map[index] | other_map[index];
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ dest_map[index] |= other_map[index];
+ }
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ dest_map[limit] = merge_tail_of_map(orig | other_map[limit], orig, rest);
}
}
-
void BitMap::set_difference(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size_in_words(); index++) {
- dest_map[index] = dest_map[index] & ~(other_map[index]);
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ dest_map[index] &= ~other_map[index];
+ }
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ dest_map[limit] = merge_tail_of_map(orig & ~other_map[limit], orig, rest);
}
}
-
void BitMap::set_intersection(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
- dest_map[index] = dest_map[index] & other_map[index];
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ dest_map[index] &= other_map[index];
}
-}
-
-
-void BitMap::set_intersection_at_offset(const BitMap& other, idx_t offset) {
- assert(other.size() >= offset, "offset not in range");
- assert(other.size() - offset >= size(), "other not large enough");
- // XXX Ideally, we would remove this restriction.
- guarantee((offset % (sizeof(bm_word_t) * BitsPerByte)) == 0,
- "Only handle aligned cases so far.");
- bm_word_t* dest_map = map();
- const bm_word_t* other_map = other.map();
- idx_t offset_word_ind = word_index(offset);
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
- dest_map[index] = dest_map[index] & other_map[offset_word_ind + index];
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ dest_map[limit] = merge_tail_of_map(orig & other_map[limit], orig, rest);
}
}
@@ -455,88 +477,111 @@ bool BitMap::set_union_with_result(const BitMap& other) {
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
- idx_t temp = dest_map[index] | other_map[index];
- changed = changed || (temp != dest_map[index]);
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ bm_word_t orig = dest_map[index];
+ bm_word_t temp = orig | other_map[index];
+ changed = changed || (temp != orig);
dest_map[index] = temp;
}
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ bm_word_t temp = merge_tail_of_map(orig | other_map[limit], orig, rest);
+ changed = changed || (temp != orig);
+ dest_map[limit] = temp;
+ }
return changed;
}
-
bool BitMap::set_difference_with_result(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
- bm_word_t temp = dest_map[index] & ~(other_map[index]);
- changed = changed || (temp != dest_map[index]);
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ bm_word_t orig = dest_map[index];
+ bm_word_t temp = orig & ~other_map[index];
+ changed = changed || (temp != orig);
dest_map[index] = temp;
}
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ bm_word_t temp = merge_tail_of_map(orig & ~other_map[limit], orig, rest);
+ changed = changed || (temp != orig);
+ dest_map[limit] = temp;
+ }
return changed;
}
-
bool BitMap::set_intersection_with_result(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
bm_word_t orig = dest_map[index];
bm_word_t temp = orig & other_map[index];
changed = changed || (temp != orig);
- dest_map[index] = temp;
+ dest_map[index] = temp;
+ }
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ bm_word_t orig = dest_map[limit];
+ bm_word_t temp = merge_tail_of_map(orig & other_map[limit], orig, rest);
+ changed = changed || (temp != orig);
+ dest_map[limit] = temp;
}
return changed;
}
-
void BitMap::set_from(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
- dest_map[index] = other_map[index];
+ idx_t copy_words = word_index(size());
+ Copy::disjoint_words((HeapWord*)other_map, (HeapWord*)dest_map, copy_words);
+ idx_t rest = bit_in_word(size());
+ if (rest > 0) {
+ dest_map[copy_words] = merge_tail_of_map(other_map[copy_words],
+ dest_map[copy_words],
+ rest);
}
}
-
-bool BitMap::is_same(const BitMap& other) {
+bool BitMap::is_same(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
- bm_word_t* dest_map = map();
+ const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
- idx_t size = size_in_words();
- for (idx_t index = 0; index < size; index++) {
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
if (dest_map[index] != other_map[index]) return false;
}
- return true;
+ idx_t rest = bit_in_word(size());
+ return (rest == 0) || (tail_of_map(dest_map[limit] ^ other_map[limit], rest) == 0);
}
bool BitMap::is_full() const {
- const bm_word_t* word = map();
- idx_t rest = size();
- for (; rest >= (idx_t) BitsPerWord; rest -= BitsPerWord) {
- if (*word != ~(bm_word_t)0) return false;
- word++;
+ const bm_word_t* words = map();
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ if (~words[index] != 0) return false;
}
- return rest == 0 || (*word | ~right_n_bits((int)rest)) == ~(bm_word_t)0;
+ idx_t rest = bit_in_word(size());
+ return (rest == 0) || (tail_of_map(~words[limit], rest) == 0);
}
-
bool BitMap::is_empty() const {
- const bm_word_t* word = map();
- idx_t rest = size();
- for (; rest >= (idx_t) BitsPerWord; rest -= BitsPerWord) {
- if (*word != 0) return false;
- word++;
+ const bm_word_t* words = map();
+ idx_t limit = word_index(size());
+ for (idx_t index = 0; index < limit; ++index) {
+ if (words[index] != 0) return false;
}
- return rest == 0 || (*word & right_n_bits((int)rest)) == 0;
+ idx_t rest = bit_in_word(size());
+ return (rest == 0) || (tail_of_map(words[limit], rest) == 0);
}
void BitMap::clear_large() {
diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp
index 01c94dae19c..919a54cd483 100644
--- a/hotspot/src/share/vm/utilities/bitMap.hpp
+++ b/hotspot/src/share/vm/utilities/bitMap.hpp
@@ -284,18 +284,9 @@ class BitMap VALUE_OBJ_CLASS_SPEC {
bool set_difference_with_result(const BitMap& bits);
bool set_intersection_with_result(const BitMap& bits);
- // Requires the submap of "bits" starting at offset to be at least as
- // large as "this". Modifies "this" to be the intersection of its
- // current contents and the submap of "bits" starting at "offset" of the
- // same length as "this."
- // (For expedience, currently requires the offset to be aligned to the
- // bitsize of a uintptr_t. This should go away in the future though it
- // will probably remain a good case to optimize.)
- void set_intersection_at_offset(const BitMap& bits, idx_t offset);
-
void set_from(const BitMap& bits);
- bool is_same(const BitMap& bits);
+ bool is_same(const BitMap& bits) const;
// Test if all bits are set or cleared
bool is_full() const;
diff --git a/hotspot/test/native/utilities/test_bitMap_setops.cpp b/hotspot/test/native/utilities/test_bitMap_setops.cpp
new file mode 100644
index 00000000000..45b6d79a444
--- /dev/null
+++ b/hotspot/test/native/utilities/test_bitMap_setops.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "utilities/bitMap.inline.hpp"
+#include "utilities/copy.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include
+#include "unittest.hpp"
+
+typedef BitMap::idx_t idx_t;
+typedef BitMap::bm_word_t bm_word_t;
+
+class BitMapMemory {
+private:
+ idx_t _words;
+ bm_word_t* _memory;
+
+public:
+ BitMapMemory(idx_t bits) :
+ _words(BitMap::calc_size_in_words(bits)),
+ _memory(static_cast(malloc(_words * sizeof(bm_word_t))))
+ { }
+
+ ~BitMapMemory() {
+ free(_memory);
+ }
+
+ BitMapView make_view(idx_t bits, bm_word_t value) {
+ vmassert(BitMap::calc_size_in_words(bits) <= _words, "invalid request");
+ STATIC_ASSERT(sizeof(bm_word_t) == sizeof(HeapWord));
+ Copy::fill_to_aligned_words((HeapWord*)_memory, _words, value);
+ return BitMapView(_memory, bits);
+ }
+
+ bm_word_t* memory() { return _memory; }
+};
+
+const idx_t aligned_size = 4 * BitsPerWord;
+const idx_t unaligned_size = aligned_size - (BitsPerWord / 2);
+
+static bm_word_t make_even_bits() {
+ bm_word_t result = 1;
+ while (true) {
+ bm_word_t next = (result << 2) | 1;
+ if (next == result) {
+ return result;
+ }
+ result = next;
+ }
+}
+
+const bm_word_t even_bits = make_even_bits();
+const bm_word_t odd_bits = ~even_bits;
+const bm_word_t one_bits = ~bm_word_t(0);
+const bm_word_t zero_bits = 0;
+
+// Scoped set a clear bit and restore to clear.
+class WithBitSet {
+private:
+ BitMap& _bm;
+ idx_t _index;
+
+public:
+ WithBitSet(BitMap& bm, idx_t index) : _bm(bm), _index(index) {
+ // Failure may indicate test bug; can't use ASSERT_xxx in constructor.
+ EXPECT_FALSE(_bm.at(_index));
+ bm.set_bit(_index);
+ }
+
+ ~WithBitSet() {
+ _bm.clear_bit(_index);
+ }
+};
+
+// Scoped clear a set bit and restore to set.
+class WithBitClear {
+private:
+ BitMap& _bm;
+ idx_t _index;
+
+public:
+ WithBitClear(BitMap& bm, idx_t index) : _bm(bm), _index(index) {
+ // Failure may indicate test bug; can't use ASSERT_xxx in constructor.
+ EXPECT_TRUE(_bm.at(_index));
+ bm.clear_bit(_index);
+ }
+
+ ~WithBitClear() {
+ _bm.set_bit(_index);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// bool is_same(const BitMap& bits);
+
+TEST(BitMap, is_same__aligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(aligned_size, even_bits);
+ BitMapView y = my.make_view(aligned_size, even_bits);
+ EXPECT_TRUE(x.is_same(y));
+
+ WithBitClear wbc(x, aligned_size / 2);
+ EXPECT_FALSE(x.is_same(y));
+}
+
+TEST(BitMap, is_same__unaligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(unaligned_size, even_bits);
+ BitMapView y = my.make_view(unaligned_size, even_bits);
+
+ // Check that a difference beyond the end of x/y doesn't count.
+ {
+ BitMapView aligned = BitMapView(mx.memory(), aligned_size);
+ const idx_t index = aligned_size - 2;
+ STATIC_ASSERT(unaligned_size <= index);
+
+ WithBitClear wbc(aligned, index);
+ EXPECT_TRUE(x.is_same(y));
+ }
+
+ // Check that a difference in the final partial word does count.
+ {
+ idx_t index = unaligned_size - 2;
+ ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
+
+ WithBitClear wbc(y, index);
+ EXPECT_FALSE(x.is_same(y));
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// bool is_full();
+// bool is_empty();
+
+TEST(BitMap, is_full_or_empty__aligned) {
+ BitMapMemory mx(aligned_size);
+
+ {
+ BitMapView x = mx.make_view(aligned_size, even_bits);
+ EXPECT_FALSE(x.is_full());
+ EXPECT_FALSE(x.is_empty());
+ }
+
+ {
+ BitMapView x = mx.make_view(aligned_size, zero_bits);
+ EXPECT_FALSE(x.is_full());
+ EXPECT_TRUE(x.is_empty());
+ }
+
+ {
+ BitMapView x = mx.make_view(aligned_size, one_bits);
+ EXPECT_TRUE(x.is_full());
+ EXPECT_FALSE(x.is_empty());
+ }
+}
+
+TEST(BitMap, is_full__unaligned) {
+ BitMapMemory mx(aligned_size);
+
+ BitMapView x = mx.make_view(unaligned_size, one_bits);
+ EXPECT_TRUE(x.is_full());
+
+ // Check that a missing bit beyond the end doesn't count.
+ {
+ idx_t index = aligned_size - 1;
+ BitMapView aligned = BitMapView(mx.memory(), aligned_size);
+
+ WithBitClear wcb(aligned, index);
+ EXPECT_FALSE(aligned.is_full());
+ EXPECT_TRUE(x.is_full());
+ }
+
+ // Check that a missing bit in the final partial word does count.
+ {
+ WithBitClear wcb(x, unaligned_size - 1);
+ EXPECT_FALSE(x.is_full());
+ }
+}
+
+TEST(BitMap, is_empty__unaligned) {
+ BitMapMemory mx(aligned_size);
+
+ BitMapView x = mx.make_view(unaligned_size, zero_bits);
+ EXPECT_TRUE(x.is_empty());
+
+ // Check that a set bit beyond the end doesn't count.
+ {
+ idx_t index = aligned_size - 1;
+ BitMapView aligned = BitMapView(mx.memory(), aligned_size);
+
+ WithBitSet wbs(aligned, index);
+ EXPECT_FALSE(aligned.is_empty());
+ EXPECT_TRUE(x.is_empty());
+ }
+
+ // Check that a set bit in the final partial word does count.
+ {
+ WithBitSet wbs(x, unaligned_size - 1);
+ EXPECT_FALSE(x.is_empty());
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// bool contains(const BitMap& bits);
+
+TEST(BitMap, contains__aligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(aligned_size, even_bits);
+ BitMapView y = my.make_view(aligned_size, even_bits);
+ EXPECT_TRUE(x.contains(y));
+
+ WithBitClear wbc(x, aligned_size / 2);
+ EXPECT_FALSE(x.contains(y));
+}
+
+TEST(BitMap, contains__unaligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(unaligned_size, even_bits);
+ BitMapView y = my.make_view(unaligned_size, even_bits);
+
+ // Check that a missing bit beyond the end of x doesn't count.
+ {
+ BitMapView aligned = BitMapView(mx.memory(), aligned_size);
+ const idx_t index = aligned_size - 2;
+ STATIC_ASSERT(unaligned_size <= index);
+
+ WithBitClear wbc(aligned, index);
+ EXPECT_TRUE(x.contains(y));
+ }
+
+ // Check that a missing bit in the final partial word does count.
+ {
+ idx_t index = unaligned_size - 2;
+ ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
+
+ WithBitClear wbc(x, index);
+ EXPECT_FALSE(x.contains(y));
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// bool intersects(const BitMap& bits);
+
+TEST(BitMap, intersects__aligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(aligned_size, even_bits);
+ BitMapView y = my.make_view(aligned_size, zero_bits);
+ EXPECT_FALSE(x.intersects(y));
+
+ ASSERT_TRUE(x.at(aligned_size / 2));
+ WithBitSet wbs(y, aligned_size / 2);
+ EXPECT_TRUE(x.intersects(y));
+}
+
+TEST(BitMap, intersects__unaligned) {
+ BitMapMemory mx(aligned_size);
+ BitMapMemory my(aligned_size);
+
+ BitMapView x = mx.make_view(unaligned_size, even_bits);
+ BitMapView y = my.make_view(unaligned_size, zero_bits);
+ EXPECT_FALSE(x.intersects(y));
+
+ // Check that adding a bit beyond the end of y doesn't count.
+ {
+ BitMapView aligned_x = BitMapView(mx.memory(), aligned_size);
+ BitMapView aligned_y = BitMapView(my.memory(), aligned_size);
+ const idx_t index = aligned_size - 2;
+ STATIC_ASSERT(unaligned_size <= index);
+ ASSERT_TRUE(aligned_x.at(index));
+
+ WithBitSet wbs(aligned_y, index);
+ EXPECT_FALSE(x.intersects(y));
+ }
+
+ // Check that adding a bit in the final partial word does count.
+ {
+ idx_t index = unaligned_size - 2;
+ ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
+ ASSERT_TRUE(x.at(index));
+
+ WithBitSet wbs(y, index);
+ EXPECT_TRUE(x.intersects(y));
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// void set_from(const BitMap& bits);
+// void set_union(const BitMap& bits);
+// void set_difference(const BitMap& bits);
+// void set_intersection(const BitMap& bits);
+//
+// bool set_union_with_result(const BitMap& bits);
+// bool set_difference_with_result(const BitMap& bits);
+// bool set_intersection_with_result(const BitMap& bits);
+
+static void check_tail_unmodified(BitMapMemory& mem,
+ idx_t bits,
+ bm_word_t fill_word) {
+ if (!BitMap::is_word_aligned(bits)) {
+ idx_t last_word_bit_index = BitMap::word_align_down(bits);
+ idx_t last_word_index = BitMap::calc_size_in_words(last_word_bit_index);
+ bm_word_t last_word = mem.memory()[last_word_index];
+ idx_t shift = bits - last_word_bit_index;
+ EXPECT_EQ(fill_word >> shift, last_word >> shift);
+ }
+}
+
+static void check_mod_setop(void (BitMap::*f)(const BitMap&),
+ idx_t bits,
+ bm_word_t wx,
+ bm_word_t wy,
+ bm_word_t wexp) {
+ BitMapMemory mx(bits);
+ BitMapMemory my(bits);
+ BitMapMemory mexp(bits);
+
+ BitMapView x = mx.make_view(bits, wx);
+ BitMapView y = my.make_view(bits, wy);
+ BitMapView exp = mexp.make_view(bits, wexp);
+
+ (x.*f)(y);
+
+ EXPECT_TRUE(exp.is_same(x));
+ check_tail_unmodified(mx, bits, wx);
+}
+
+static void check_mod_setop_with_result(bool (BitMap::*f)(const BitMap&),
+ idx_t bits,
+ bm_word_t wx,
+ bm_word_t wy,
+ bm_word_t wexp) {
+ BitMapMemory mx(bits);
+ BitMapMemory my(bits);
+ BitMapMemory mexp(bits);
+
+ BitMapView x = mx.make_view(bits, wx);
+ BitMapView y = my.make_view(bits, wy);
+ BitMapView exp = mexp.make_view(bits, wexp);
+
+ bool value = (x.*f)(y);
+ EXPECT_EQ(value, wx != wexp);
+
+ EXPECT_TRUE(exp.is_same(x));
+ check_tail_unmodified(mx, bits, wx);
+}
+
+#define CHECK_MOD_SETOP_AUX(checker, name, x, y, exp) \
+ TEST(BitMap, name ## __ ## x ## _ ## y) { \
+ checker(&BitMap::name, aligned_size, \
+ x ## _bits, y ## _bits, exp ## _bits); \
+ checker(&BitMap::name, unaligned_size, \
+ x ## _bits, y ## _bits, exp ## _bits); \
+ }
+
+#define CHECK_MOD_SETOP(name, x, y, exp) \
+ CHECK_MOD_SETOP_AUX(check_mod_setop, name, x, y, exp)
+
+#define CHECK_MOD_SETOP_WITH_RESULT(name, x, y, exp) \
+ CHECK_MOD_SETOP_AUX(check_mod_setop_with_result, name, x, y, exp)
+
+#define CHECK_MOD_SETOPS(name, x, y, exp) \
+ CHECK_MOD_SETOP(name, x, y, exp) \
+ CHECK_MOD_SETOP_WITH_RESULT(name ## _with_result, x, y, exp)
+
+CHECK_MOD_SETOP(set_from, even, even, even)
+CHECK_MOD_SETOP(set_from, even, odd, odd)
+CHECK_MOD_SETOP(set_from, even, one, one)
+CHECK_MOD_SETOP(set_from, even, zero, zero)
+
+CHECK_MOD_SETOPS(set_union, even, even, even)
+CHECK_MOD_SETOPS(set_union, even, odd, one)
+CHECK_MOD_SETOPS(set_union, even, one, one)
+CHECK_MOD_SETOPS(set_union, even, zero, even)
+
+CHECK_MOD_SETOPS(set_difference, even, even, zero)
+CHECK_MOD_SETOPS(set_difference, even, odd, even)
+CHECK_MOD_SETOPS(set_difference, even, one, zero)
+CHECK_MOD_SETOPS(set_difference, even, zero, even)
+
+CHECK_MOD_SETOPS(set_intersection, even, even, even)
+CHECK_MOD_SETOPS(set_intersection, even, odd, zero)
+CHECK_MOD_SETOPS(set_intersection, even, one, even)
+CHECK_MOD_SETOPS(set_intersection, even, zero, zero)
+
diff --git a/hotspot/test/runtime/RedefineTests/ModifyAnonymous.java b/hotspot/test/runtime/RedefineTests/ModifyAnonymous.java
new file mode 100644
index 00000000000..700a8f04e93
--- /dev/null
+++ b/hotspot/test/runtime/RedefineTests/ModifyAnonymous.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @summary Test that retransforming and redefining anonymous classes gets UnmodifiableClassException
+ * @modules java.base/jdk.internal.misc
+ * @modules java.instrument
+ * jdk.jartool/sun.tools.jar
+ * @run main ModifyAnonymous buildagent
+ * @run main/othervm -javaagent:redefineagent.jar ModifyAnonymous
+ */
+
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.lang.NoSuchFieldException;
+import java.lang.NoSuchMethodException;
+import java.lang.RuntimeException;
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+import jdk.test.lib.*;
+
+public class ModifyAnonymous {
+
+ public static class LambdaTransformer implements ClassFileTransformer {
+ @Override
+ public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer)
+ throws IllegalClassFormatException {
+ return null;
+ }
+ }
+
+ static Instrumentation inst = null;
+ static volatile boolean done = false;
+
+ public static void premain(String args, Instrumentation instrumentation) {
+
+ inst = instrumentation;
+ System.out.println("javaagent in da house!");
+ instrumentation.addTransformer(new LambdaTransformer());
+ }
+
+ private static void buildAgent() {
+ try {
+ ClassFileInstaller.main("ModifyAnonymous");
+ } catch (Exception e) {
+ throw new RuntimeException("Could not write agent classfile", e);
+ }
+
+ try {
+ PrintWriter pw = new PrintWriter("MANIFEST.MF");
+ pw.println("Premain-Class: ModifyAnonymous");
+ pw.println("Agent-Class: ModifyAnonymous");
+ pw.println("Can-Retransform-Classes: true");
+ pw.println("Can-Redefine-Classes: true");
+ pw.close();
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException("Could not write manifest file for the agent", e);
+ }
+
+ sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+ if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "ModifyAnonymous.class" })) {
+ throw new RuntimeException("Could not write the agent jar file");
+ }
+ }
+
+ public static class InstanceMethodCallSiteApp {
+
+ public static void test() throws InterruptedException {
+ for (int i = 0; i < 2; i++) {
+ InstanceMethodCallSiteApp app = new InstanceMethodCallSiteApp();
+ Runnable r = app::doWork; // this creates an anonymous class
+ while (!done) {
+ r.run();
+ Thread.sleep(10);
+ }
+ }
+ }
+
+ public void doWork() {
+ System.out.print(".");
+ }
+ }
+
+ static void runTest() {
+ while (!done) {
+ Class[] allLoadedClasses = inst.getAllLoadedClasses();
+ for (Class clazz : allLoadedClasses) {
+ final String name = clazz.getName();
+ if (name.contains("$$Lambda$") && name.contains("App")) {
+ if (inst.isModifiableClass(clazz)) {
+ throw new RuntimeException ("Class should not be modifiable");
+ }
+ // Try to modify them anyway.
+ try {
+ System.out.println("retransform called for " + name);
+ inst.retransformClasses(clazz);
+ } catch(java.lang.instrument.UnmodifiableClassException t) {
+ System.out.println("PASSED: expecting UnmodifiableClassException");
+ t.printStackTrace();
+ }
+ try {
+ System.out.println("redefine called for " + name);
+ String newclass = "class Dummy {}";
+ byte[] bytecode = InMemoryJavaCompiler.compile("Dummy", newclass);
+ ClassDefinition cld = new ClassDefinition(clazz, bytecode);
+ inst.redefineClasses(new ClassDefinition[] { cld });
+ } catch(java.lang.instrument.UnmodifiableClassException t) {
+ System.out.println("PASSED: expecting UnmodifiableClassException");
+ t.printStackTrace();
+ } catch(java.lang.ClassNotFoundException e) {
+ throw new RuntimeException ("ClassNotFoundException thrown");
+ }
+ done = true;
+ }
+ }
+ }
+ }
+
+ public static void main(String argv[]) throws InterruptedException, RuntimeException {
+ if (argv.length == 1 && argv[0].equals("buildagent")) {
+ buildAgent();
+ return;
+ }
+
+ if (inst == null) {
+ throw new RuntimeException("Instrumentation object was null");
+ }
+
+ new Thread() {
+ public void run() {
+ runTest();
+ }
+ }.start();
+
+ // Test that NCDFE is not thrown for anonymous class:
+ // ModifyAnonymous$InstanceMethodCallSiteApp$$Lambda$18
+ try {
+ ModifyAnonymous test = new ModifyAnonymous();
+ InstanceMethodCallSiteApp.test();
+ } catch (NoClassDefFoundError e) {
+ throw new RuntimeException("FAILED: NoClassDefFoundError thrown for " + e.getMessage());
+ }
+ System.out.println("PASSED: NoClassDefFound error not thrown");
+ }
+}
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index bfe5860fa48..380d39ea6ab 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -374,3 +374,4 @@ bdc3c0b737efbf899709eb3121ce760dcfb51151 jdk-9+127
74241304e87b0d463391a8ecab40979b5af86dc2 jdk-9+129
e66cdc2de6b02443911d386fc9217b0d824d0686 jdk-9+130
874082a9b565a7092a40bfa934a6e3e3c3455a60 jdk-9+131
+907445d85e680ea410fe2c83c0ec64b5508e4f3e jdk-9+132
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/res/XSLTErrorResources.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/res/XSLTErrorResources.java
index 1a85fc3ba9b..5ef374f3fae 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/res/XSLTErrorResources.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/res/XSLTErrorResources.java
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: XSLTErrorResources.java,v 1.2.4.1 2005/09/13 09:55:37 pvedula Exp $
- */
package com.sun.org.apache.xalan.internal.res;
import java.util.ListResourceBundle;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
index cf83580147f..52f944101dc 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: ErrorMessages.java,v 1.2.4.1 2005/09/15 09:59:41 pvedula Exp $
- */
package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/ErrorMessages.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/ErrorMessages.java
index e1fd9e38df3..fe98ae968c0 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/ErrorMessages.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/ErrorMessages.java
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: ErrorMessages.java,v 1.2.4.1 2005/09/14 05:06:42 pvedula Exp $
- */
package com.sun.org.apache.xalan.internal.xsltc.runtime;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AbortException.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AbortException.java
new file mode 100644
index 00000000000..3e178dd8d71
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AbortException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.org.apache.xerces.internal.dom;
+
+public class AbortException extends RuntimeException {
+
+ private static final long serialVersionUID = 2608302175475740417L;
+
+ /**
+ * Constructor AbortException
+ */
+ public AbortException() { super(null, null, false, false); }
+}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DOMNormalizer.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DOMNormalizer.java
index 1e4fc39be62..c2f33916772 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DOMNormalizer.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DOMNormalizer.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.io.StringReader;
import java.util.Vector;
+import com.sun.org.apache.xerces.internal.dom.AbortException;
import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
import com.sun.org.apache.xerces.internal.impl.dtd.DTDGrammar;
@@ -157,11 +158,6 @@ public class DOMNormalizer implements XMLDocumentHandler {
// attribute value normalization
final XMLString fNormalizedValue = new XMLString(new char[16], 0, 0);
- /**
- * If the user stops the process, this exception will be thrown.
- */
- public static final RuntimeException abort = new RuntimeException();
-
//DTD validator
private XMLDTDValidator fDTDValidator;
@@ -242,11 +238,8 @@ public class DOMNormalizer implements XMLDocumentHandler {
XMLGrammarDescription.XML_SCHEMA, fValidationHandler);
fValidationHandler = null;
}
- }
- catch (RuntimeException e) {
- if( e==abort )
- return; // processing aborted by the user
- throw e; // otherwise re-throw.
+ } catch (AbortException e) {
+ return;
}
}
@@ -1371,10 +1364,10 @@ public class DOMNormalizer implements XMLDocumentHandler {
error.fRelatedData = locator.fRelatedNode;
if(!errorHandler.handleError(error))
- throw abort;
+ throw new AbortException();
}
if( severity==DOMError.SEVERITY_FATAL_ERROR )
- throw abort;
+ throw new AbortException();
}
protected final void updateQName (Node node, QName qname){
@@ -2043,5 +2036,4 @@ public class DOMNormalizer implements XMLDocumentHandler {
return null;
}
-
} // DOMNormalizer class
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DOMMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DOMMessages.properties
index 9d6841b5fb1..1bd94b8a314 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DOMMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DOMMessages.properties
@@ -2,8 +2,6 @@
# DOM implementation.
#
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: DOMMessages.properties,v 1.2 2005-08-16 22:51:51 jeffsuttor Exp $
BadMessageKey = The error message corresponding to the message key can not be found.
FormatFailed = An internal error occurred while formatting the following message:\n
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DatatypeMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DatatypeMessages.properties
index 0a601e178a3..72b20151706 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DatatypeMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/DatatypeMessages.properties
@@ -1,8 +1,6 @@
# This file stores localized messages for the Xerces JAXP Datatype API implementation.
#
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: DatatypeMessages.properties 3021 2011-03-01 00:12:28Z joehw $
BadMessageKey = The error message corresponding to the message key can not be found.
FormatFailed = An internal error occurred while formatting the following message:\n
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/JAXPValidationMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/JAXPValidationMessages.properties
index bdc6c454b6c..60ae45af330 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/JAXPValidationMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/JAXPValidationMessages.properties
@@ -1,8 +1,6 @@
# This file stores localized messages for the Xerces JAXP Validation API implementation.
#
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: JAXPValidationMessages.properties 3021 2011-03-01 00:12:28Z joehw $
# Messages for message reporting
BadMessageKey = The error message corresponding to the message key can not be found.
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/SAXMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/SAXMessages.properties
index 2373f367b9b..c0c1ad14cd8 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/SAXMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/SAXMessages.properties
@@ -2,8 +2,6 @@
# SAX implementation.
#
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: SAXMessages.properties 3021 2011-03-01 00:12:28Z joehw $
BadMessageKey = The error message corresponding to the message key can not be found.
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
index 0b09746f11d..423728021cf 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
@@ -1,7 +1,5 @@
# This file contains error and warning messages related to XML Schema
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: XMLSchemaMessages.properties 3021 2011-03-01 00:12:28Z joehw $
BadMessageKey = The error message corresponding to the message key can not be found.
FormatFailed = An internal error occurred while formatting the following message:\n
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSerializerMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSerializerMessages.properties
index caad2621a8d..2d81d83628b 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSerializerMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSerializerMessages.properties
@@ -4,8 +4,6 @@
#
# As usual with properties files, the messages are arranged in
# key/value tuples.
-#
-# @version $Id: XMLSerializerMessages.properties 3021 2011-03-01 00:12:28Z joehw $
BadMessageKey = The error message corresponding to the message key can not be found.
FormatFailed = An internal error occurred while formatting the following message:\n
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XPointerMessages.properties b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XPointerMessages.properties
index 1ae480d2bc8..7fe755ebb99 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XPointerMessages.properties
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XPointerMessages.properties
@@ -1,8 +1,6 @@
# This file stores localized messages for the Xerces XPointer implementation.
#
# The messages are arranged in key and value tuples in a ListResourceBundle.
-#
-# @version $Id: XPointerMessages.properties 3021 2011-03-01 00:12:28Z joehw $
# Messages for message reporting
BadMessageKey = The error message corresponding to the message key can not be found.
@@ -24,4 +22,4 @@ InvalidElementSchemeToken = InvalidElementSchemeToken: The element() scheme XPoi
InvalidElementSchemeXPointer = InvalidElementSchemeXPointer: The Element Scheme XPointer expression ''{0}'' is invalid.
XPointerElementSchemeProcessingError = XPointerElementSchemeProcessingError: An error occurred while processing the XPointer element() Scheme expression.
InvalidNCNameInElementSchemeData = InvalidNCNameInElementSchemeData: The element() Scheme contains a ShortHand Pointer ''{0}'' with an invalid NCName.
-InvalidChildSequenceCharacter = InvalidChildSequenceCharacter: The element() Scheme contains an invalid child sequence character ''{0}''.
\ No newline at end of file
+InvalidChildSequenceCharacter = InvalidChildSequenceCharacter: The element() Scheme contains an invalid child sequence character ''{0}''.
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/res/XMLErrorResources.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/res/XMLErrorResources.java
index 8d1ab9b948d..1c83bc50917 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/res/XMLErrorResources.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/res/XMLErrorResources.java
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: XMLErrorResources.java,v 1.2.4.1 2005/09/15 07:45:37 suresh_emailid Exp $
- */
package com.sun.org.apache.xml.internal.res;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
index 926019e7290..6c2eaf15c53 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
@@ -28,6 +28,7 @@ import java.io.Writer;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import com.sun.org.apache.xerces.internal.dom.AbortException;
import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl;
import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl;
@@ -501,11 +502,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
} catch (LSException lse) {
// Rethrow LSException.
throw lse;
+ } catch (AbortException e) {
+ return null;
} catch (RuntimeException e) {
- if (e == DOMNormalizer.abort) {
- // stopped at user request
- return null;
- }
throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
} catch (IOException ioe) {
// REVISIT: A generic IOException doesn't provide enough information
@@ -733,11 +732,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
} catch (LSException lse) {
// Rethrow LSException.
throw lse;
+ } catch (AbortException e) {
+ return false;
} catch (RuntimeException e) {
- if (e == DOMNormalizer.abort) {
- // stopped at user request
- return false;
- }
throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
} catch (Exception e) {
if (ser.fDOMErrorHandler != null) {
@@ -833,11 +830,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
} catch (LSException lse) {
// Rethrow LSException.
throw lse;
+ } catch (AbortException e) {
+ return false;
} catch (RuntimeException e) {
- if (e == DOMNormalizer.abort) {
- // stopped at user request
- return false;
- }
throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
} catch (Exception e) {
if (ser.fDOMErrorHandler != null) {
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/utils/SerializerMessages.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/utils/SerializerMessages.java
index 60e6955ce1d..e7d50361d81 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/utils/SerializerMessages.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/utils/SerializerMessages.java
@@ -19,9 +19,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: SerializerMessages.java,v 1.1.4.1 2005/09/08 11:03:11 suresh_emailid Exp $
- */
package com.sun.org.apache.xml.internal.serializer.utils;
import java.util.ListResourceBundle;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
index 9192e968b7f..38f72b729f7 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
@@ -28,6 +28,7 @@ package com.sun.org.apache.xpath.internal.jaxp;
import com.sun.org.apache.xalan.internal.res.XSLMessages;
import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTM;
+import com.sun.org.apache.xpath.internal.axes.LocPathIterator;
import com.sun.org.apache.xpath.internal.objects.XObject;
import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
import java.io.IOException;
@@ -73,6 +74,12 @@ class XPathImplUtil {
XObject eval(Object contextItem, com.sun.org.apache.xpath.internal.XPath xpath)
throws javax.xml.transform.TransformerException {
com.sun.org.apache.xpath.internal.XPathContext xpathSupport;
+ if (contextItem == null && xpath.getExpression() instanceof LocPathIterator) {
+ // the operation must have no dependency on the context that is null
+ throw new TransformerException(XSLMessages.createXPATHMessage(
+ XPATHErrorResources.ER_CONTEXT_CAN_NOT_BE_NULL,
+ new Object[] {}));
+ }
if (functionResolver != null) {
JAXPExtensionsProvider jep = new JAXPExtensionsProvider(
functionResolver, featureSecureProcessing, featureManager);
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java
index 68b4853f3d9..0c084ecaf2d 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: XPATHErrorResources.java,v 1.2.4.1 2005/09/15 01:29:15 jeffsuttor Exp $
- */
package com.sun.org.apache.xpath.internal.res;
import java.util.ListResourceBundle;
@@ -93,6 +90,7 @@ public class XPATHErrorResources extends ListResourceBundle
public static final String ER_CURRENT_TAKES_NO_ARGS =
"ER_CURRENT_TAKES_NO_ARGS";
public static final String ER_DOCUMENT_REPLACED = "ER_DOCUMENT_REPLACED";
+ public static final String ER_CONTEXT_CAN_NOT_BE_NULL = "ER_CONTEXT_CAN_NOT_BE_NULL";
public static final String ER_CONTEXT_HAS_NO_OWNERDOC =
"ER_CONTEXT_HAS_NO_OWNERDOC";
public static final String ER_LOCALNAME_HAS_TOO_MANY_ARGS =
@@ -368,6 +366,9 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_DOCUMENT_REPLACED,
"document() function implementation has been replaced by com.sun.org.apache.xalan.internal.xslt.FuncDocument!"},
+ { ER_CONTEXT_CAN_NOT_BE_NULL,
+ "The context can not be null when the operation is context-dependent."},
+
{ ER_CONTEXT_HAS_NO_OWNERDOC,
"context does not have an owner document!"},
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
index 92c89ea1274..d7c0a44bf95 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,18 +34,20 @@ import org.xml.sax.InputSource;
*
*
*
- *
- *
- *
Evaluation of XPath Expressions.
- *
- *
- *
- *
context
- *
- * If a request is made to evaluate the expression in the absence
- * of a context item, an empty document node will be used for the context.
- * For the purposes of evaluating XPath expressions, a DocumentFragment
- * is treated like a Document node.
+ *
+ *
+ *
Evaluation of XPath Expressions.
+ *
+ *
+ *
+ *
context
+ *
+ * The type of the context is implementation-dependent. If the value is
+ * null, the operation must have no dependency on the context, otherwise
+ * an XPathExpressionException will be thrown.
+ *
+ * For the purposes of evaluating XPath expressions, a DocumentFragment
+ * is treated like a Document node.
*
*
*
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
index 1a60f13ca48..697745e92d5 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,19 +33,20 @@ import org.xml.sax.InputSource;
*
*
*
- *
- *
- *
Evaluation of XPath Expressions.
- *
- *
- *
- *
- *
context
- *
- * If a request is made to evaluate the expression in the absence
- * of a context item, an empty document node will be used for the context.
- * For the purposes of evaluating XPath expressions, a DocumentFragment
- * is treated like a Document node.
+ *
+ *
+ *
Evaluation of XPath Expressions.
+ *
+ *
+ *
+ *
context
+ *
+ * The type of the context is implementation-dependent. If the value is
+ * null, the operation must have no dependency on the context, otherwise
+ * an XPathExpressionException will be thrown.
+ *
+ * For the purposes of evaluating XPath expressions, a DocumentFragment
+ * is treated like a Document node.
*
*
*
diff --git a/jaxp/src/java.xml/share/classes/module-info.java b/jaxp/src/java.xml/share/classes/module-info.java
index ed48672adfc..40ca6421302 100644
--- a/jaxp/src/java.xml/share/classes/module-info.java
+++ b/jaxp/src/java.xml/share/classes/module-info.java
@@ -23,6 +23,10 @@
* questions.
*/
+/**
+ * Defines the Java API for XML Processing (JAXP), the Streaming API for XML (StAX),
+ * the Simple API for XML (SAX), and the W3C Document Object Model (DOM) API.
+ */
module java.xml {
exports javax.xml;
exports javax.xml.catalog;
diff --git a/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java b/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java
index a6c80541968..ea961181569 100644
--- a/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java
+++ b/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java
@@ -24,11 +24,17 @@
package xpath;
import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
-
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
/*
* @test
@@ -36,19 +42,105 @@ import org.testng.annotations.Test;
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
* @run testng/othervm -DrunSecMngr=true xpath.XPathTest
* @run testng/othervm xpath.XPathTest
- * @summary Test XPath.getNamespaceContext() is supported.
+ * @summary Test XPath functions. See details for each test.
*/
@Listeners({jaxp.library.BasePolicy.class})
public class XPathTest {
+ /*
+ @bug 6211561
+ * Verifies the specification for XPath and XPathExpression:
+ * If a null value is provided for item (the context),
+ * the expression must have no dependency on the context.
+ */
+ @Test(dataProvider = "noContextDependency")
+ public void testNoContextDependency1(String expression, Object item) throws XPathExpressionException {
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ xPath.evaluate(expression, item, XPathConstants.STRING);
+ }
+
+ @Test(dataProvider = "noContextDependency")
+ public void testNoContextDependency2(String expression, Object item) throws XPathExpressionException {
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ xPath.evaluateExpression(expression, item, String.class);
+ }
+
+ /*
+ @bug 6211561
+ * Verifies the specification for XPath and XPathExpression:
+ * If a null value is provided for item (the context) that the operation
+ * depends on, XPathExpressionException will be thrown
+ */
+ @Test(dataProvider = "hasContextDependency", expectedExceptions = XPathExpressionException.class)
+ public void testHasContextDependency1(String expression, Object item) throws XPathExpressionException {
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ xPath.evaluate(expression, item, XPathConstants.STRING);
+ }
+
+ @Test(dataProvider = "hasContextDependency", expectedExceptions = XPathExpressionException.class)
+ public void testHasContextDependency2(String expression, Object item) throws XPathExpressionException {
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ xPath.evaluateExpression(expression, item, String.class);
+ }
+
+ /*
+ @bug 6376058
+ Verifies that XPath.getNamespaceContext() is supported.
+ */
@Test
public void testNamespaceContext() {
-
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
-
NamespaceContext namespaceContext = xPath.getNamespaceContext();
+ }
+ /*
+ * DataProvider: the expression has no dependency on the context
+ */
+ @DataProvider(name = "noContextDependency")
+ public Object[][] getExpressionContext() throws Exception {
+ return new Object[][]{
+ {"1+1", (Node)null},
+ {"5 mod 2", (Node)null},
+ {"8 div 2", (Node)null},
+ {"/node", getEmptyDocument()}
+ };
+ }
+
+ /*
+ * DataProvider: the expression has dependency on the context, but the context
+ * is null.
+ */
+ @DataProvider(name = "hasContextDependency")
+ public Object[][] getExpressionContext1() throws Exception {
+ return new Object[][]{
+ {"/node", (Node)null},
+ {"//@lang", (Node)null},
+ {"bookstore//book", (Node)null},
+ {"/bookstore/book[last()]", (Node)null},
+ {"//title[@lang='en']", (Node)null},
+ {"/bookstore/book[price>9.99]", (Node)null},
+ {"/bookstore/book[price>8.99 and price<9.99]", (Node)null},
+ {"/bookstore/*", (Node)null},
+ {"//title[@*]", (Node)null},
+ {"//title | //price", (Node)null},
+ {"//book/title | //book/price", (Node)null},
+ {"/bookstore/book/title | //price", (Node)null},
+ {"child::book", (Node)null},
+ {"child::text()", (Node)null},
+ {"child::*/child::price", (Node)null}
+ };
+ }
+
+ /**
+ * Returns an empty {@link org.w3c.dom.Document}.
+ * @return a DOM Document, null in case of Exception
+ */
+ public Document getEmptyDocument() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ return null;
+ }
}
}
-
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 0b957319e81..36eb74d3bb0 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -377,3 +377,4 @@ fe4e11bd2423635dc0f5f5cb9a64eb2f2cce7f4c jdk-9+128
46a02f57218e4a8c334dbccf656fb048f823f163 jdk-9+129
39c6293131d91aec7f2f5120395e070a937b8858 jdk-9+130
783e7e2c587f2c7e1b9998a46d90ec196ab2a195 jdk-9+131
+9fff2477a4cadf2a9618a76f1f4fe0f20bb5ff3b jdk-9+132
diff --git a/jaxws/src/java.activation/share/classes/module-info.java b/jaxws/src/java.activation/share/classes/module-info.java
index d6507874caa..dca632ee776 100644
--- a/jaxws/src/java.activation/share/classes/module-info.java
+++ b/jaxws/src/java.activation/share/classes/module-info.java
@@ -23,6 +23,9 @@
* questions.
*/
+/**
+ * Defines the JavaBeans Activation Framework (JAF) API.
+ */
module java.activation {
requires public java.datatransfer;
// dependence on java.beans.Beans to be eliminated
diff --git a/jaxws/src/java.annotations.common/share/classes/module-info.java b/jaxws/src/java.annotations.common/share/classes/module-info.java
index 0a3a8dd3c6e..fddb78c5efc 100644
--- a/jaxws/src/java.annotations.common/share/classes/module-info.java
+++ b/jaxws/src/java.annotations.common/share/classes/module-info.java
@@ -23,6 +23,10 @@
* questions.
*/
+/**
+ * Defines a subset of the Common Annotations API to support programs running
+ * on the Java SE Platform.
+ */
module java.annotations.common {
exports javax.annotation;
}
diff --git a/jaxws/src/java.xml.bind/share/classes/module-info.java b/jaxws/src/java.xml.bind/share/classes/module-info.java
index 7f7cde8190e..708945a98fc 100644
--- a/jaxws/src/java.xml.bind/share/classes/module-info.java
+++ b/jaxws/src/java.xml.bind/share/classes/module-info.java
@@ -23,6 +23,9 @@
* questions.
*/
+/**
+ * Defines the Java Architecture for XML Binding (JAXB) API.
+ */
module java.xml.bind {
requires public java.activation;
requires public java.xml;
diff --git a/jaxws/src/java.xml.ws/share/classes/module-info.java b/jaxws/src/java.xml.ws/share/classes/module-info.java
index 799e0f23395..cba0cdecb08 100644
--- a/jaxws/src/java.xml.ws/share/classes/module-info.java
+++ b/jaxws/src/java.xml.ws/share/classes/module-info.java
@@ -23,6 +23,10 @@
* questions.
*/
+/**
+ * Defines the Java API for XML-Based Web Services (JAX-WS), and
+ * the Web Services Metadata API.
+ */
module java.xml.ws {
requires public java.activation;
requires public java.xml;
diff --git a/jdk/.hgtags b/jdk/.hgtags
index b82ddf4e57c..d0c1a581878 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -374,3 +374,4 @@ c40c8739bcdc88892ff58ebee3fd8a3f287be94d jdk-9+123
47699aa2e69ec2702542dc73eb01de3bfb61aea0 jdk-9+129
6c827500e34587061af97ad6fef0e859280255c5 jdk-9+130
8c57f4c293bbc5609928308a6d91ba765760b5f9 jdk-9+131
+d5c70818cd8a82e76632c8c815bdb4f75f53aeaf jdk-9+132
diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk
index 5fb26d4b4d2..c023e8cfbed 100644
--- a/jdk/make/copy/Copy-java.base.gmk
+++ b/jdk/make/copy/Copy-java.base.gmk
@@ -183,7 +183,7 @@ DEF_POLICY_DST := $(LIB_DST_DIR)/security/default.policy
DEF_POLICY_SRC_LIST := $(DEF_POLICY_SRC)
-ifeq ($(OPENJDK_TARGET_OS), windows)
+ifneq ($(filter $(OPENJDK_TARGET_OS), windows solaris), )
DEF_POLICY_SRC_LIST += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/lib/security/default.policy
endif
diff --git a/jdk/src/java.base/macosx/classes/apple/security/AppleProvider.java b/jdk/src/java.base/macosx/classes/apple/security/AppleProvider.java
index 12dc2592a3b..3b712846d45 100644
--- a/jdk/src/java.base/macosx/classes/apple/security/AppleProvider.java
+++ b/jdk/src/java.base/macosx/classes/apple/security/AppleProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package apple.security;
import java.security.*;
+import static sun.security.util.SecurityConstants.PROVIDER_VER;
/**
* The Apple Security Provider.
@@ -74,7 +75,7 @@ public final class AppleProvider extends Provider {
public AppleProvider() {
/* We are the Apple provider */
- super("Apple", 9.0d, info);
+ super("Apple", PROVIDER_VER, info);
final Provider p = this;
AccessController.doPrivileged(new PrivilegedAction() {
diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
index 134a60096c2..9d82ebb6ff2 100644
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -107,7 +107,12 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
throw new InvalidKeySpecException("Key length is negative");
}
try {
- this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
+ this.prf = Mac.getInstance(prfAlgo);
+ // SunPKCS11 requires a non-empty PBE password
+ if (passwdBytes.length == 0 &&
+ this.prf.getProvider().getName().startsWith("SunPKCS11")) {
+ this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
+ }
} catch (NoSuchAlgorithmException nsae) {
// not gonna happen; re-throw just in case
InvalidKeySpecException ike = new InvalidKeySpecException();
diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
index e7ab016b5d9..e44a8476dc2 100644
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@ package com.sun.crypto.provider;
import java.security.AccessController;
import java.security.Provider;
import java.security.SecureRandom;
+import static sun.security.util.SecurityConstants.PROVIDER_VER;
/**
@@ -104,7 +105,7 @@ public final class SunJCE extends Provider {
public SunJCE() {
/* We are the "SunJCE" provider */
- super("SunJCE", 9.0d, info);
+ super("SunJCE", PROVIDER_VER, info);
final String BLOCK_MODES = "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" +
"|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" +
diff --git a/jdk/src/java.base/share/classes/java/io/BufferedReader.java b/jdk/src/java.base/share/classes/java/io/BufferedReader.java
index 3940b3b8776..1f6a66490cd 100644
--- a/jdk/src/java.base/share/classes/java/io/BufferedReader.java
+++ b/jdk/src/java.base/share/classes/java/io/BufferedReader.java
@@ -560,7 +560,7 @@ public class BufferedReader extends Reader {
* @since 1.8
*/
public Stream lines() {
- Iterator iter = new Iterator() {
+ Iterator iter = new Iterator<>() {
String nextLine = null;
@Override
diff --git a/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
index 61a147d1c4d..bd867c08d76 100644
--- a/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
+++ b/jdk/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
@@ -187,7 +187,7 @@ public class ByteArrayOutputStream extends OutputStream {
* @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size()
*/
- public synchronized byte toByteArray()[] {
+ public synchronized byte[] toByteArray() {
return Arrays.copyOf(buf, count);
}
diff --git a/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java b/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java
index 773b59614d9..e8bf2c36167 100644
--- a/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java
+++ b/jdk/src/java.base/share/classes/java/io/CharArrayWriter.java
@@ -165,7 +165,7 @@ class CharArrayWriter extends Writer {
*
* @param csq
* The character sequence to append. If {@code csq} is
- * {@code null}, then the four characters "{@code null}" are
+ * {@code null}, then the four characters {@code "null"} are
* appended to this writer.
*
* @return This writer
@@ -173,7 +173,7 @@ class CharArrayWriter extends Writer {
* @since 1.5
*/
public CharArrayWriter append(CharSequence csq) {
- String s = (csq == null ? "null" : csq.toString());
+ String s = String.valueOf(csq);
write(s, 0, s.length());
return this;
}
@@ -193,7 +193,7 @@ class CharArrayWriter extends Writer {
* The character sequence from which a subsequence will be
* appended. If {@code csq} is {@code null}, then characters
* will be appended as if {@code csq} contained the four
- * characters "{@code null}".
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -212,9 +212,8 @@ class CharArrayWriter extends Writer {
* @since 1.5
*/
public CharArrayWriter append(CharSequence csq, int start, int end) {
- String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
- write(s, 0, s.length());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
@@ -251,7 +250,7 @@ class CharArrayWriter extends Writer {
*
* @return an array of chars copied from the input data.
*/
- public char toCharArray()[] {
+ public char[] toCharArray() {
synchronized (lock) {
return Arrays.copyOf(buf, count);
}
diff --git a/jdk/src/java.base/share/classes/java/io/FileSystem.java b/jdk/src/java.base/share/classes/java/io/FileSystem.java
index 9d73e79ed40..a7528a9b5ca 100644
--- a/jdk/src/java.base/share/classes/java/io/FileSystem.java
+++ b/jdk/src/java.base/share/classes/java/io/FileSystem.java
@@ -228,13 +228,8 @@ abstract class FileSystem {
static boolean useCanonPrefixCache = true;
private static boolean getBooleanProperty(String prop, boolean defaultVal) {
- String val = System.getProperty(prop);
- if (val == null) return defaultVal;
- if (val.equalsIgnoreCase("true")) {
- return true;
- } else {
- return false;
- }
+ return Boolean.parseBoolean(System.getProperty(prop,
+ String.valueOf(defaultVal)));
}
static {
diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java
index 9f13c9216a3..1895203cd11 100644
--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java
@@ -1265,22 +1265,21 @@ public class ObjectInputStream
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
Boolean result = Caches.subclassAudits.get(key);
if (result == null) {
- result = Boolean.valueOf(auditSubclass(cl));
+ result = auditSubclass(cl);
Caches.subclassAudits.putIfAbsent(key, result);
}
- if (result.booleanValue()) {
- return;
+ if (!result) {
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
- sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
/**
* Performs reflective checks on given subclass to verify that it doesn't
- * override security-sensitive non-final methods. Returns true if subclass
- * is "safe", false otherwise.
+ * override security-sensitive non-final methods. Returns TRUE if subclass
+ * is "safe", FALSE otherwise.
*/
- private static boolean auditSubclass(final Class> subcl) {
- Boolean result = AccessController.doPrivileged(
+ private static Boolean auditSubclass(Class> subcl) {
+ return AccessController.doPrivileged(
new PrivilegedAction<>() {
public Boolean run() {
for (Class> cl = subcl;
@@ -1303,7 +1302,6 @@ public class ObjectInputStream
}
}
);
- return result.booleanValue();
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java
index 2fc905e2dd3..bff6f8311ee 100644
--- a/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java
+++ b/jdk/src/java.base/share/classes/java/io/ObjectOutputStream.java
@@ -1050,22 +1050,21 @@ public class ObjectOutputStream
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
Boolean result = Caches.subclassAudits.get(key);
if (result == null) {
- result = Boolean.valueOf(auditSubclass(cl));
+ result = auditSubclass(cl);
Caches.subclassAudits.putIfAbsent(key, result);
}
- if (result.booleanValue()) {
- return;
+ if (!result) {
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
- sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
/**
* Performs reflective checks on given subclass to verify that it doesn't
- * override security-sensitive non-final methods. Returns true if subclass
- * is "safe", false otherwise.
+ * override security-sensitive non-final methods. Returns TRUE if subclass
+ * is "safe", FALSE otherwise.
*/
- private static boolean auditSubclass(final Class> subcl) {
- Boolean result = AccessController.doPrivileged(
+ private static Boolean auditSubclass(Class> subcl) {
+ return AccessController.doPrivileged(
new PrivilegedAction<>() {
public Boolean run() {
for (Class> cl = subcl;
@@ -1088,7 +1087,6 @@ public class ObjectOutputStream
}
}
);
- return result.booleanValue();
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java
index cca42a71bbf..7ae45cae8c4 100644
--- a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java
@@ -1509,11 +1509,9 @@ public class ObjectStreamClass implements Serializable {
private static String getPackageName(Class> cl) {
String s = cl.getName();
int i = s.lastIndexOf('[');
- if (i >= 0) {
- s = s.substring(i + 2);
- }
- i = s.lastIndexOf('.');
- return (i >= 0) ? s.substring(0, i) : "";
+ i = (i < 0) ? 0 : i + 2;
+ int j = s.lastIndexOf('.');
+ return (i < j) ? s.substring(i, j) : "";
}
/**
@@ -1535,14 +1533,14 @@ public class ObjectStreamClass implements Serializable {
private static String getMethodSignature(Class>[] paramTypes,
Class> retType)
{
- StringBuilder sbuf = new StringBuilder();
- sbuf.append('(');
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
for (int i = 0; i < paramTypes.length; i++) {
- appendClassSignature(sbuf, paramTypes[i]);
+ appendClassSignature(sb, paramTypes[i]);
}
- sbuf.append(')');
- appendClassSignature(sbuf, retType);
- return sbuf.toString();
+ sb.append(')');
+ appendClassSignature(sb, retType);
+ return sb.toString();
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java
index 4fdb148baaf..3d44f443b82 100644
--- a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java
+++ b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java
@@ -233,22 +233,16 @@ public class OutputStreamWriter extends Writer {
@Override
public Writer append(CharSequence csq, int start, int end) throws IOException {
- if (csq == null) {
- write("null".subSequence(start, end).toString());
- return this;
- } else {
- return append(csq.subSequence(start, end));
- }
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
@Override
public Writer append(CharSequence csq) throws IOException {
- if (csq == null) {
- se.write("null");
- } else if (csq instanceof CharBuffer) {
+ if (csq instanceof CharBuffer) {
se.write((CharBuffer) csq);
} else {
- se.write(csq.toString());
+ se.write(String.valueOf(csq));
}
return this;
}
diff --git a/jdk/src/java.base/share/classes/java/io/PrintStream.java b/jdk/src/java.base/share/classes/java/io/PrintStream.java
index 36a271e804d..09028de7358 100644
--- a/jdk/src/java.base/share/classes/java/io/PrintStream.java
+++ b/jdk/src/java.base/share/classes/java/io/PrintStream.java
@@ -568,7 +568,7 @@ public class PrintStream extends FilterOutputStream
* @param b The {@code boolean} to be printed
*/
public void print(boolean b) {
- write(b ? "true" : "false");
+ write(String.valueOf(b));
}
/**
@@ -663,10 +663,7 @@ public class PrintStream extends FilterOutputStream
* @param s The {@code String} to be printed
*/
public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
+ write(String.valueOf(s));
}
/**
@@ -1068,10 +1065,7 @@ public class PrintStream extends FilterOutputStream
* @since 1.5
*/
public PrintStream append(CharSequence csq) {
- if (csq == null)
- print("null");
- else
- print(csq.toString());
+ print(String.valueOf(csq));
return this;
}
@@ -1111,9 +1105,8 @@ public class PrintStream extends FilterOutputStream
* @since 1.5
*/
public PrintStream append(CharSequence csq, int start, int end) {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/PrintWriter.java b/jdk/src/java.base/share/classes/java/io/PrintWriter.java
index d516b8ef404..0513312781b 100644
--- a/jdk/src/java.base/share/classes/java/io/PrintWriter.java
+++ b/jdk/src/java.base/share/classes/java/io/PrintWriter.java
@@ -504,7 +504,7 @@ public class PrintWriter extends Writer {
* @param b The {@code boolean} to be printed
*/
public void print(boolean b) {
- write(b ? "true" : "false");
+ write(String.valueOf(b));
}
/**
@@ -599,10 +599,7 @@ public class PrintWriter extends Writer {
* @param s The {@code String} to be printed
*/
public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
+ write(String.valueOf(s));
}
/**
@@ -1005,10 +1002,7 @@ public class PrintWriter extends Writer {
* @since 1.5
*/
public PrintWriter append(CharSequence csq) {
- if (csq == null)
- write("null");
- else
- write(csq.toString());
+ write(String.valueOf(csq));
return this;
}
@@ -1047,9 +1041,8 @@ public class PrintWriter extends Writer {
* @since 1.5
*/
public PrintWriter append(CharSequence csq, int start, int end) {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/SequenceInputStream.java b/jdk/src/java.base/share/classes/java/io/SequenceInputStream.java
index f68f7d25265..b2caa11bca9 100644
--- a/jdk/src/java.base/share/classes/java/io/SequenceInputStream.java
+++ b/jdk/src/java.base/share/classes/java/io/SequenceInputStream.java
@@ -65,12 +65,7 @@ class SequenceInputStream extends InputStream {
*/
public SequenceInputStream(Enumeration extends InputStream> e) {
this.e = e;
- try {
- nextStream();
- } catch (IOException ex) {
- // This should never happen
- throw new Error("panic");
- }
+ peekNextStream();
}
/**
@@ -86,16 +81,10 @@ class SequenceInputStream extends InputStream {
*/
public SequenceInputStream(InputStream s1, InputStream s2) {
Vector v = new Vector<>(2);
-
v.addElement(s1);
v.addElement(s2);
e = v.elements();
- try {
- nextStream();
- } catch (IOException ex) {
- // This should never happen
- throw new Error("panic");
- }
+ peekNextStream();
}
/**
@@ -105,14 +94,17 @@ class SequenceInputStream extends InputStream {
if (in != null) {
in.close();
}
+ peekNextStream();
+ }
+ private void peekNextStream() {
if (e.hasMoreElements()) {
in = (InputStream) e.nextElement();
if (in == null)
throw new NullPointerException();
+ } else {
+ in = null;
}
- else in = null;
-
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/StringBufferInputStream.java b/jdk/src/java.base/share/classes/java/io/StringBufferInputStream.java
index 787cbb9c45e..11c230ff932 100644
--- a/jdk/src/java.base/share/classes/java/io/StringBufferInputStream.java
+++ b/jdk/src/java.base/share/classes/java/io/StringBufferInputStream.java
@@ -108,6 +108,7 @@ class StringBufferInputStream extends InputStream {
* -1 if there is no more data because the end of
* the stream has been reached.
*/
+ @SuppressWarnings("deprecation")
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
@@ -126,12 +127,8 @@ class StringBufferInputStream extends InputStream {
if (len <= 0) {
return 0;
}
- String s = buffer;
- int cnt = len;
- while (--cnt >= 0) {
- b[off++] = (byte)s.charAt(pos++);
- }
-
+ buffer.getBytes(pos, pos + len, b, off);
+ pos += len;
return len;
}
diff --git a/jdk/src/java.base/share/classes/java/io/StringReader.java b/jdk/src/java.base/share/classes/java/io/StringReader.java
index 2dd72ff5357..9cfe5412993 100644
--- a/jdk/src/java.base/share/classes/java/io/StringReader.java
+++ b/jdk/src/java.base/share/classes/java/io/StringReader.java
@@ -142,8 +142,8 @@ public class StringReader extends Reader {
*/
public boolean ready() throws IOException {
synchronized (lock) {
- ensureOpen();
- return true;
+ ensureOpen();
+ return true;
}
}
diff --git a/jdk/src/java.base/share/classes/java/io/StringWriter.java b/jdk/src/java.base/share/classes/java/io/StringWriter.java
index 15022b353a8..16eed62d7bb 100644
--- a/jdk/src/java.base/share/classes/java/io/StringWriter.java
+++ b/jdk/src/java.base/share/classes/java/io/StringWriter.java
@@ -139,7 +139,7 @@ public class StringWriter extends Writer {
*
* @param csq
* The character sequence to append. If {@code csq} is
- * {@code null}, then the four characters "{@code null}" are
+ * {@code null}, then the four characters {@code "null"} are
* appended to this writer.
*
* @return This writer
@@ -147,10 +147,7 @@ public class StringWriter extends Writer {
* @since 1.5
*/
public StringWriter append(CharSequence csq) {
- if (csq == null)
- write("null");
- else
- write(csq.toString());
+ write(String.valueOf(csq));
return this;
}
@@ -170,7 +167,7 @@ public class StringWriter extends Writer {
* The character sequence from which a subsequence will be
* appended. If {@code csq} is {@code null}, then characters
* will be appended as if {@code csq} contained the four
- * characters "{@code null}".
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -189,9 +186,8 @@ public class StringWriter extends Writer {
* @since 1.5
*/
public StringWriter append(CharSequence csq, int start, int end) {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
diff --git a/jdk/src/java.base/share/classes/java/io/Writer.java b/jdk/src/java.base/share/classes/java/io/Writer.java
index 17e8de3ef8a..cd9aded358f 100644
--- a/jdk/src/java.base/share/classes/java/io/Writer.java
+++ b/jdk/src/java.base/share/classes/java/io/Writer.java
@@ -221,7 +221,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
*
* @param csq
* The character sequence to append. If {@code csq} is
- * {@code null}, then the four characters "{@code null}" are
+ * {@code null}, then the four characters {@code "null"} are
* appended to this writer.
*
* @return This writer
@@ -232,10 +232,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* @since 1.5
*/
public Writer append(CharSequence csq) throws IOException {
- if (csq == null)
- write("null");
- else
- write(csq.toString());
+ write(String.valueOf(csq));
return this;
}
@@ -256,7 +253,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* The character sequence from which a subsequence will be
* appended. If {@code csq} is {@code null}, then characters
* will be appended as if {@code csq} contained the four
- * characters "{@code null}".
+ * characters {@code "null"}.
*
* @param start
* The index of the first character in the subsequence
@@ -278,9 +275,8 @@ public abstract class Writer implements Appendable, Closeable, Flushable {
* @since 1.5
*/
public Writer append(CharSequence csq, int start, int end) throws IOException {
- CharSequence cs = (csq == null ? "null" : csq);
- write(cs.subSequence(start, end).toString());
- return this;
+ if (csq == null) csq = "null";
+ return append(csq.subSequence(start, end));
}
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
index 3b6fad7a636..91071a2b3b4 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
@@ -36,7 +36,6 @@ import sun.invoke.util.Wrapper;
import java.lang.invoke.LambdaForm.NamedFunction;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
-import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -308,7 +307,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
/*non-public*/ char fieldTypeChar(int i) {
return typeChars.charAt(i);
}
- Object fieldSignature() {
+ String fieldSignature() {
return typeChars;
}
public Class extends BoundMethodHandle> fieldHolder() {
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java
index 2e4baec0857..d11012e6487 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java
@@ -27,6 +27,7 @@ package java.lang.invoke;
import java.util.Arrays;
import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.Kind.*;
import static java.lang.invoke.MethodHandleStatics.*;
/**
@@ -96,14 +97,8 @@ abstract class DelegatingMethodHandle extends MethodHandle {
int whichCache,
Object constraint,
NamedFunction getTargetFn) {
- String debugString;
- switch(whichCache) {
- case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
- case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
- default: debugString = "MH.reinvoke"; break;
- }
// No pre-action needed.
- return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
+ return makeReinvokerForm(target, whichCache, constraint, null, true, getTargetFn, null);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target,
@@ -114,6 +109,10 @@ abstract class DelegatingMethodHandle extends MethodHandle {
NamedFunction getTargetFn,
NamedFunction preActionFn) {
MethodType mtype = target.type().basicType();
+ Kind kind = whichKind(whichCache);
+ if (debugString == null) {
+ debugString = kind.defaultLambdaName;
+ }
boolean customized = (whichCache < 0 ||
mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
boolean hasPreAction = (preActionFn != null);
@@ -145,13 +144,21 @@ abstract class DelegatingMethodHandle extends MethodHandle {
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
}
- form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
+ form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline, kind);
if (!customized) {
form = mtype.form().setCachedLambdaForm(whichCache, form);
}
return form;
}
+ private static Kind whichKind(int whichCache) {
+ switch(whichCache) {
+ case MethodTypeForm.LF_REBIND: return BOUND_REINVOKER;
+ case MethodTypeForm.LF_DELEGATE: return DELEGATE;
+ default: return REINVOKER;
+ }
+ }
+
static final NamedFunction NF_getTarget;
static {
try {
@@ -160,5 +167,13 @@ abstract class DelegatingMethodHandle extends MethodHandle {
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
+ // The Holder class will contain pre-generated DelegatingMethodHandles resolved
+ // speculatively using MemberName.getFactory().resolveOrNull. However, that
+ // doesn't initialize the class, which subtly breaks inlining etc. By forcing
+ // initialization of the Holder class we avoid these issues.
+ UNSAFE.ensureClassInitialized(Holder.class);
}
+
+ /* Placeholder class for DelegatingMethodHandles generated ahead of time */
+ final class Holder {}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
index 494103f57cc..174e914f805 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
@@ -38,6 +38,7 @@ import java.util.Arrays;
import java.util.Objects;
import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.Kind.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
import static java.lang.invoke.MethodHandleStatics.newInternalError;
@@ -189,14 +190,15 @@ class DirectMethodHandle extends MethodHandle {
static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
boolean needsInit = (which == LF_INVSTATIC_INIT);
boolean doesAlloc = (which == LF_NEWINVSPECIAL);
- String linkerName, lambdaName;
+ String linkerName;
+ LambdaForm.Kind kind;
switch (which) {
- case LF_INVVIRTUAL: linkerName = "linkToVirtual"; lambdaName = "DMH.invokeVirtual"; break;
- case LF_INVSTATIC: linkerName = "linkToStatic"; lambdaName = "DMH.invokeStatic"; break;
- case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; lambdaName = "DMH.invokeStaticInit"; break;
- case LF_INVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.invokeSpecial"; break;
- case LF_INVINTERFACE: linkerName = "linkToInterface"; lambdaName = "DMH.invokeInterface"; break;
- case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.newInvokeSpecial"; break;
+ case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break;
+ case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break;
+ case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC_INIT; break;
+ case LF_INVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_INVOKE_SPECIAL; break;
+ case LF_INVINTERFACE: linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE; break;
+ case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_NEW_INVOKE_SPECIAL; break;
default: throw new InternalError("which="+which);
}
@@ -240,11 +242,11 @@ class DirectMethodHandle extends MethodHandle {
result = NEW_OBJ;
}
names[LINKER_CALL] = new Name(linker, outArgs);
- lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
- LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
+ String lambdaName = kind.defaultLambdaName + "_" + shortenSignature(basicTypeSignature(mtype));
+ LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result, kind);
// This is a tricky bit of code. Don't send it through the LF interpreter.
- lform.compileToBytecode(Holder.class);
+ lform.compileToBytecode();
return lform;
}
@@ -705,7 +707,7 @@ class DirectMethodHandle extends MethodHandle {
}
static {
- // The DMH class will contain pre-generated DirectMethodHandles resolved
+ // The Holder class will contain pre-generated DirectMethodHandles resolved
// speculatively using MemberName.getFactory().resolveOrNull. However, that
// doesn't initialize the class, which subtly breaks inlining etc. By forcing
// initialization of the Holder class we avoid these issues.
@@ -713,5 +715,5 @@ class DirectMethodHandle extends MethodHandle {
}
/* Placeholder class for DirectMethodHandles generated ahead of time */
- private final class Holder {}
+ final class Holder {}
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
index 5edf33c8c60..714e6268d25 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
@@ -29,21 +29,82 @@ import java.util.Map;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
+import java.util.ArrayList;
+import java.util.HashSet;
+
/**
* Helper class to assist the GenerateJLIClassesPlugin to get access to
* generate classes ahead of time.
*/
class GenerateJLIClassesHelper {
- static byte[] generateDMHClassBytes(String className,
+ static byte[] generateBasicFormsClassBytes(String className) {
+ ArrayList forms = new ArrayList<>();
+ ArrayList names = new ArrayList<>();
+ HashSet dedupSet = new HashSet<>();
+ for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) {
+ LambdaForm zero = LambdaForm.zeroForm(type);
+ String name = zero.kind.defaultLambdaName
+ + "_" + zero.returnType().basicTypeChar();
+ if (dedupSet.add(name)) {
+ names.add(name);
+ forms.add(zero);
+ }
+
+ LambdaForm identity = LambdaForm.identityForm(type);
+ name = identity.kind.defaultLambdaName
+ + "_" + identity.returnType().basicTypeChar();
+ if (dedupSet.add(name)) {
+ names.add(name);
+ forms.add(identity);
+ }
+ }
+ return generateCodeBytesForLFs(className,
+ names.toArray(new String[0]),
+ forms.toArray(new LambdaForm[0]));
+ }
+
+ static byte[] generateDirectMethodHandleHolderClassBytes(String className,
MethodType[] methodTypes, int[] types) {
LambdaForm[] forms = new LambdaForm[methodTypes.length];
+ String[] names = new String[methodTypes.length];
for (int i = 0; i < forms.length; i++) {
forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i],
types[i]);
- methodTypes[i] = forms[i].methodType();
+ names[i] = forms[i].kind.defaultLambdaName;
}
- return generateCodeBytesForLFs(className, forms, methodTypes);
+ return generateCodeBytesForLFs(className, names, forms);
+ }
+
+ static byte[] generateDelegatingMethodHandleHolderClassBytes(String className,
+ MethodType[] methodTypes) {
+
+ HashSet dedupSet = new HashSet<>();
+ ArrayList forms = new ArrayList<>();
+ ArrayList names = new ArrayList<>();
+ for (int i = 0; i < methodTypes.length; i++) {
+ // generate methods representing the DelegatingMethodHandle
+ if (dedupSet.add(methodTypes[i])) {
+ // reinvokers are variant with the associated SpeciesData
+ // and shape of the target LF, but we can easily pregenerate
+ // the basic reinvokers associated with Species_L. Ultimately we
+ // may want to consider pregenerating more of these, which will
+ // require an even more complex naming scheme
+ LambdaForm reinvoker = makeReinvokerFor(methodTypes[i]);
+ forms.add(reinvoker);
+ String speciesSig = BoundMethodHandle
+ .speciesData(reinvoker).fieldSignature();
+ assert(speciesSig.equals("L"));
+ names.add(reinvoker.kind.defaultLambdaName + "_" + speciesSig);
+
+ LambdaForm delegate = makeDelegateFor(methodTypes[i]);
+ forms.add(delegate);
+ names.add(delegate.kind.defaultLambdaName);
+ }
+ }
+ return generateCodeBytesForLFs(className,
+ names.toArray(new String[0]),
+ forms.toArray(new LambdaForm[0]));
}
/*
@@ -51,22 +112,45 @@ class GenerateJLIClassesHelper {
* a class with a specified name.
*/
private static byte[] generateCodeBytesForLFs(String className,
- LambdaForm[] forms, MethodType[] types) {
- assert(forms.length == types.length);
+ String[] names, LambdaForm[] forms) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null);
cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null);
+
for (int i = 0; i < forms.length; i++) {
- InvokerBytecodeGenerator g
- = new InvokerBytecodeGenerator(className, forms[i], types[i]);
- g.setClassWriter(cw);
- g.addMethod();
+ addMethod(className, names[i], forms[i],
+ forms[i].methodType(), cw);
}
return cw.toByteArray();
}
+ private static void addMethod(String className, String methodName, LambdaForm form,
+ MethodType type, ClassWriter cw) {
+ InvokerBytecodeGenerator g
+ = new InvokerBytecodeGenerator(className, methodName, form, type);
+ g.setClassWriter(cw);
+ g.addMethod();
+ }
+
+ private static LambdaForm makeReinvokerFor(MethodType type) {
+ MethodHandle emptyHandle = MethodHandles.empty(type);
+ return DelegatingMethodHandle.makeReinvokerForm(emptyHandle,
+ MethodTypeForm.LF_REBIND,
+ BoundMethodHandle.speciesData_L(),
+ BoundMethodHandle.speciesData_L().getterFunction(0));
+ }
+
+ private static LambdaForm makeDelegateFor(MethodType type) {
+ MethodHandle handle = MethodHandles.empty(type);
+ return DelegatingMethodHandle.makeReinvokerForm(
+ handle,
+ MethodTypeForm.LF_DELEGATE,
+ DelegatingMethodHandle.class,
+ DelegatingMethodHandle.NF_getTarget);
+ }
+
static Map.Entry generateConcreteBMHClassBytes(
final String types) {
for (char c : types.toCharArray()) {
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
index 3508a11b049..6b9a2703be2 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
@@ -46,6 +46,7 @@ import java.util.stream.Stream;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.BasicType.*;
+import static java.lang.invoke.LambdaForm.Kind.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
@@ -125,9 +126,15 @@ class InvokerBytecodeGenerator {
}
/** For generating customized code for a single LambdaForm. */
- InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
+ private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
+ this(className, form.debugName, form, invokerType);
+ }
+
+ /** For generating customized code for a single LambdaForm. */
+ InvokerBytecodeGenerator(String className, String invokerName,
+ LambdaForm form, MethodType invokerType) {
this(form, form.names.length,
- className, form.debugName, invokerType);
+ className, invokerName, invokerType);
// Create an array to map name indexes to locals indexes.
Name[] names = form.names;
for (int i = 0, index = 0; i < localsMap.length; i++) {
@@ -597,10 +604,47 @@ class InvokerBytecodeGenerator {
return c.getName().replace('.', '/');
}
+ private static MemberName resolveFrom(String name, MethodType type, Class> holder) {
+ MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
+ MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder);
+
+ return resolvedMember;
+ }
+
+ private static MemberName lookupPregenerated(LambdaForm form) {
+ if (form.customized != null) {
+ // No pre-generated version for customized LF
+ return null;
+ }
+ MethodType invokerType = form.methodType();
+ String name = form.kind.methodName;
+ switch (form.kind) {
+ case BOUND_REINVOKER: {
+ name = name + "_" + BoundMethodHandle.speciesData(form).fieldSignature();
+ return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
+ }
+ case DELEGATE: return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
+ case ZERO: // fall-through
+ case IDENTITY: {
+ name = name + "_" + form.returnType().basicTypeChar();
+ return resolveFrom(name, invokerType, LambdaForm.Holder.class);
+ }
+ case DIRECT_INVOKE_INTERFACE: // fall-through
+ case DIRECT_INVOKE_SPECIAL: // fall-through
+ case DIRECT_INVOKE_STATIC: // fall-through
+ case DIRECT_INVOKE_STATIC_INIT: // fall-through
+ case DIRECT_INVOKE_VIRTUAL: return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class);
+ }
+ return null;
+ }
+
/**
* Generate customized bytecode for a given LambdaForm.
*/
static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
+ MemberName pregenerated = lookupPregenerated(form);
+ if (pregenerated != null) return pregenerated; // pre-generated bytecode
+
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
return g.loadMethod(g.generateCustomizedCodeBytes());
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java
index a007881252f..a7c84c823ea 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java
@@ -41,6 +41,7 @@ import java.util.HashMap;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
import static java.lang.invoke.MethodHandleStatics.*;
+import java.util.Objects;
/**
* The symbolic, non-executable form of a method handle's invocation semantics.
@@ -127,6 +128,7 @@ class LambdaForm {
final MethodHandle customized;
@Stable final Name[] names;
final String debugName;
+ final Kind kind;
MemberName vmentry; // low-level behavior, or null if not yet prepared
private boolean isCompiled;
@@ -266,12 +268,48 @@ class LambdaForm {
}
}
+ enum Kind {
+ GENERIC(""),
+ ZERO("zero"),
+ IDENTITY("identity"),
+ BOUND_REINVOKER("BMH.reinvoke"),
+ REINVOKER("MH.reinvoke"),
+ DELEGATE("MH.delegate"),
+ DIRECT_INVOKE_VIRTUAL("DMH.invokeVirtual"),
+ DIRECT_INVOKE_SPECIAL("DMH.invokeSpecial"),
+ DIRECT_INVOKE_STATIC("DMH.invokeStatic"),
+ DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial"),
+ DIRECT_INVOKE_INTERFACE("DMH.invokeInterface"),
+ DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit");
+
+ final String defaultLambdaName;
+ final String methodName;
+
+ private Kind(String defaultLambdaName) {
+ this.defaultLambdaName = defaultLambdaName;
+ int p = defaultLambdaName.indexOf('.');
+ if (p > -1) {
+ this.methodName = defaultLambdaName.substring(p + 1);
+ } else {
+ this.methodName = defaultLambdaName;
+ }
+ }
+ }
+
LambdaForm(String debugName,
int arity, Name[] names, int result) {
- this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null);
+ this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC);
+ }
+ LambdaForm(String debugName,
+ int arity, Name[] names, int result, Kind kind) {
+ this(debugName, arity, names, result, /*forceInline=*/true, /*customized=*/null, kind);
}
LambdaForm(String debugName,
int arity, Name[] names, int result, boolean forceInline, MethodHandle customized) {
+ this(debugName, arity, names, result, forceInline, customized, Kind.GENERIC);
+ }
+ LambdaForm(String debugName,
+ int arity, Name[] names, int result, boolean forceInline, MethodHandle customized, Kind kind) {
assert(namesOK(arity, names));
this.arity = arity;
this.result = fixResult(result, names);
@@ -279,6 +317,7 @@ class LambdaForm {
this.debugName = fixDebugName(debugName);
this.forceInline = forceInline;
this.customized = customized;
+ this.kind = kind;
int maxOutArity = normalize();
if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
// Cannot use LF interpreter on very high arity expressions.
@@ -288,11 +327,15 @@ class LambdaForm {
}
LambdaForm(String debugName,
int arity, Name[] names) {
- this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null);
+ this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, Kind.GENERIC);
}
LambdaForm(String debugName,
int arity, Name[] names, boolean forceInline) {
- this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null);
+ this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null, Kind.GENERIC);
+ }
+ LambdaForm(String debugName,
+ int arity, Name[] names, boolean forceInline, Kind kind) {
+ this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null, kind);
}
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result) {
@@ -325,6 +368,7 @@ class LambdaForm {
this.debugName = "LF.zero";
this.forceInline = true;
this.customized = null;
+ this.kind = Kind.GENERIC;
assert(nameRefsAreLegal());
assert(isEmpty());
String sig = null;
@@ -395,7 +439,7 @@ class LambdaForm {
/** Customize LambdaForm for a particular MethodHandle */
LambdaForm customize(MethodHandle mh) {
- LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh);
+ LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh, kind);
if (COMPILE_THRESHOLD >= 0 && isCompiled) {
// If shared LambdaForm has been compiled, compile customized version as well.
customForm.compileToBytecode();
@@ -773,28 +817,6 @@ class LambdaForm {
}
}
- /**
- * Generate optimizable bytecode for this form after first looking for a
- * pregenerated version in a specified class.
- */
- void compileToBytecode(Class> lookupClass) {
- if (vmentry != null && isCompiled) {
- return; // already compiled somehow
- }
- MethodType invokerType = methodType();
- assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
- int dot = debugName.indexOf('.');
- String methodName = (dot > 0) ? debugName.substring(dot + 1) : debugName;
- MemberName member = new MemberName(lookupClass, methodName, invokerType, REF_invokeStatic);
- MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, lookupClass);
- if (resolvedMember != null) {
- vmentry = resolvedMember;
- isCompiled = true;
- } else {
- compileToBytecode();
- }
- }
-
private static void computeInitialPreparedForms() {
// Find all predefined invokers and associate them with canonical empty lambda forms.
for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
@@ -1828,7 +1850,7 @@ class LambdaForm {
// bootstrap dependency on this method in case we're interpreting LFs
if (isVoid) {
Name[] idNames = new Name[] { argument(0, L_TYPE) };
- idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
+ idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
@@ -1836,15 +1858,17 @@ class LambdaForm {
zeFun = idFun;
} else {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
- idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
+ idForm = new LambdaForm(idMem.getName(), 2, idNames, 1, Kind.IDENTITY);
idForm.compileToBytecode();
- idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
+ idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(
+ idMem.getInvocationType(), idForm, MethodHandleImpl.Intrinsic.IDENTITY));
Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
- zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
+ zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1, Kind.ZERO);
zeForm.compileToBytecode();
- zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm));
+ zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(
+ zeMem.getInvocationType(), zeForm, MethodHandleImpl.Intrinsic.ZERO));
}
LF_zero[ord] = zeForm;
@@ -1901,8 +1925,17 @@ class LambdaForm {
if (USE_PREDEFINED_INTERPRET_METHODS)
computeInitialPreparedForms();
NamedFunction.initializeInvokers();
+
+ // The Holder class will contain pre-generated forms resolved
+ // using MemberName.getFactory(). However, that doesn't initialize the
+ // class, which subtly breaks inlining etc. By forcing
+ // initialization of the Holder class we avoid these issues.
+ UNSAFE.ensureClassInitialized(Holder.class);
}
+ /* Placeholder class for zero and identity forms generated ahead of time */
+ final class Holder {}
+
// The following hack is necessary in order to suppress TRACE_INTERPRETER
// during execution of the static initializes of this class.
// Turning on TRACE_INTERPRETER too early will cause
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
index 60dc84f65ed..4d0c2890fdf 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -1718,10 +1718,19 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
}
@Override
- public byte[] generateDMHClassBytes(String className,
- MethodType[] methodTypes, int[] types) {
+ public byte[] generateDirectMethodHandleHolderClassBytes(
+ String className, MethodType[] methodTypes, int[] types) {
return GenerateJLIClassesHelper
- .generateDMHClassBytes(className, methodTypes, types);
+ .generateDirectMethodHandleHolderClassBytes(
+ className, methodTypes, types);
+ }
+
+ @Override
+ public byte[] generateDelegatingMethodHandleHolderClassBytes(
+ String className, MethodType[] methodTypes) {
+ return GenerateJLIClassesHelper
+ .generateDelegatingMethodHandleHolderClassBytes(
+ className, methodTypes);
}
@Override
@@ -1730,6 +1739,12 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
return GenerateJLIClassesHelper
.generateConcreteBMHClassBytes(types);
}
+
+ @Override
+ public byte[] generateBasicFormsClassBytes(final String className) {
+ return GenerateJLIClassesHelper
+ .generateBasicFormsClassBytes(className);
+ }
});
}
@@ -1925,7 +1940,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* @return whether the counter has reached the limit.
*/
static boolean countedLoopPredicate(int counter, int limit) {
- return counter <= limit;
+ return counter < limit;
}
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index 81dedf3090d..a02e2f18b23 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -4583,7 +4583,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* // assume MH_decrement is a handle to x-1 of type int
* MethodHandle[]
* indexVar = {start, MH_increment}, // i = start; i = i+1
- * loopLimit = {end, null, MH_lessThan, returnVar }, // i
{@code Provider.id name}
*
{@code String.valueOf(provider.getName())}
*
{@code Provider.id version}
- *
{@code String.valueOf(provider.getVersion())}
+ *
{@code String.valueOf(provider.getVersionStr())}
*
{@code Provider.id info}
{@code String.valueOf(provider.getInfo())}
*
{@code Provider.id className}
*
{@code provider.getClass().getName()}
*
*
- *
Each provider has a name and a version number. A provider normally
+ *
Each provider has a name and a version string. A provider normally
* identifies itself with a file named {@code java.security.Provider}
* in the resource directory {@code META-INF/services}.
* Security providers are looked up via the {@link ServiceLoader} mechanism
@@ -102,11 +102,10 @@ import java.util.function.Function;
public abstract class Provider extends Properties {
// Declare serialVersionUID to be compatible with JDK1.1
- static final long serialVersionUID = -4298000515446427739L;
+ private static final long serialVersionUID = -4298000515446427739L;
private static final sun.security.util.Debug debug =
- sun.security.util.Debug.getInstance
- ("provider", "Provider");
+ sun.security.util.Debug.getInstance("provider", "Provider");
/**
* The provider name.
@@ -129,6 +128,12 @@ public abstract class Provider extends Properties {
*/
private double version;
+ /**
+ * The provider version string.
+ *
+ * @serial
+ */
+ private String versionStr;
private transient Set> entrySet = null;
private transient int entrySetCallCount = 0;
@@ -174,19 +179,83 @@ public abstract class Provider extends Properties {
}
}
+ private static double parseVersionStr(String s) {
+ try {
+ int firstDotIdx = s.indexOf('.');
+ int nextDotIdx = s.indexOf('.', firstDotIdx + 1);
+ if (nextDotIdx != -1) {
+ s = s.substring(0, nextDotIdx);
+ }
+ int endIdx = s.indexOf('-');
+ if (endIdx > 0) {
+ s = s.substring(0, endIdx);
+ }
+ endIdx = s.indexOf('+');
+ if (endIdx > 0) {
+ s = s.substring(0, endIdx);
+ }
+ return Double.parseDouble(s);
+ } catch (NullPointerException | NumberFormatException e) {
+ return 0d;
+ }
+ }
+
/**
* Constructs a provider with the specified name, version number,
- * and information.
+ * and information. Calling this constructor is equivalent to call the
+ * {@link #Provider(String, String, String)} with {@code name}
+ * name, {@code Double.toString(version)}, and {@code info}.
*
* @param name the provider name.
*
* @param version the provider version number.
*
* @param info a description of the provider and its services.
+ *
+ * @deprecated use {@link #Provider(String, String, String)} instead.
*/
+ @Deprecated(since="9")
protected Provider(String name, double version, String info) {
this.name = name;
this.version = version;
+ this.versionStr = Double.toString(version);
+ this.info = info;
+ putId();
+ initialized = true;
+ }
+
+ /**
+ * Constructs a provider with the specified name, version string,
+ * and information.
+ *
+ *
The version string contains a version number optionally followed
+ * by other information separated by one of the characters of '+', '-'.
+ *
+ * The format for the version number is:
+ *
+ *
+ * ^[0-9]+(\.[0-9]+)*
+ *
+ *
+ *
In order to return the version number in a double, when there are
+ * more than two components (separated by '.' as defined above), only
+ * the first two components are retained. The resulting string is then
+ * passed to {@link Double#valueOf(String)} to generate version number,
+ * i.e. {@link #getVersion}.
+ *
If the conversion failed, value 0 will be used.
+ *
+ * @param name the provider name.
+ *
+ * @param versionStr the provider version string.
+ *
+ * @param info a description of the provider and its services.
+ *
+ * @since 9
+ */
+ protected Provider(String name, String versionStr, String info) {
+ this.name = name;
+ this.versionStr = versionStr;
+ this.version = parseVersionStr(versionStr);
this.info = info;
putId();
initialized = true;
@@ -250,11 +319,25 @@ public abstract class Provider extends Properties {
* Returns the version number for this provider.
*
* @return the version number for this provider.
+ *
+ * @deprecated use {@link #getVersionStr} instead.
*/
+ @Deprecated(since="9")
public double getVersion() {
return version;
}
+ /**
+ * Returns the version string for this provider.
+ *
+ * @return the version string for this provider.
+ *
+ * @since 9
+ */
+ public String getVersionStr() {
+ return versionStr;
+ }
+
/**
* Returns a human-readable description of the provider and its
* services. This may return an HTML page, with relevant links.
@@ -266,14 +349,14 @@ public abstract class Provider extends Properties {
}
/**
- * Returns a string with the name and the version number
+ * Returns a string with the name and the version string
* of this provider.
*
- * @return the string with the name and the version number
+ * @return the string with the name and the version string
* for this provider.
*/
public String toString() {
- return name + " version " + version;
+ return name + " version " + versionStr;
}
/*
@@ -601,7 +684,7 @@ public abstract class Provider extends Properties {
public synchronized Object compute(Object key, BiFunction super Object,
? super Object, ? extends Object> remappingFunction) {
check("putProviderProperty." + name);
- check("removeProviderProperty" + name);
+ check("removeProviderProperty." + name);
if (debug != null) {
debug.println("Compute " + name + " provider property " + key);
@@ -632,7 +715,7 @@ public abstract class Provider extends Properties {
public synchronized Object computeIfAbsent(Object key, Function super Object,
? extends Object> mappingFunction) {
check("putProviderProperty." + name);
- check("removeProviderProperty" + name);
+ check("removeProviderProperty." + name);
if (debug != null) {
debug.println("ComputeIfAbsent " + name + " provider property " +
@@ -662,7 +745,7 @@ public abstract class Provider extends Properties {
public synchronized Object computeIfPresent(Object key, BiFunction super Object,
? super Object, ? extends Object> remappingFunction) {
check("putProviderProperty." + name);
- check("removeProviderProperty" + name);
+ check("removeProviderProperty." + name);
if (debug != null) {
debug.println("ComputeIfPresent " + name + " provider property " +
@@ -695,7 +778,7 @@ public abstract class Provider extends Properties {
public synchronized Object merge(Object key, Object value, BiFunction super Object,
? super Object, ? extends Object> remappingFunction) {
check("putProviderProperty." + name);
- check("removeProviderProperty" + name);
+ check("removeProviderProperty." + name);
if (debug != null) {
debug.println("Merge " + name + " provider property " + key);
@@ -787,11 +870,21 @@ public abstract class Provider extends Properties {
private void putId() {
// note: name and info may be null
super.put("Provider.id name", String.valueOf(name));
- super.put("Provider.id version", String.valueOf(version));
+ super.put("Provider.id version", String.valueOf(versionStr));
super.put("Provider.id info", String.valueOf(info));
super.put("Provider.id className", this.getClass().getName());
}
+ /**
+ * Reads the {@code ObjectInputStream} for the default serializable fields.
+ * If the serialized field {@code versionStr} is found in the STREAM FIELDS,
+ * its String value will be used to populate both the version string and
+ * version number. If {@code versionStr} is not found, but {@code version}
+ * is, then its double value will be used to populate both fields.
+ *
+ * @param in the {@code ObjectInputStream} to read
+ * @serial
+ */
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
Map