8180032: Unaligned pointer dereference in ClassFileParser
Reviewed-by: dholmes, hseigel
--- a/hotspot/src/cpu/aarch64/vm/bytes_aarch64.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/aarch64/vm/bytes_aarch64.hpp Fri May 26 13:47:33 2017 -0700
@@ -30,12 +30,6 @@
class Bytes: AllStatic {
public:
- // Returns true if the byte ordering used by Java is different from the native byte ordering
- // of the underlying machine. For example, this is true for Intel x86, but false for Solaris
- // on Sparc.
- static inline bool is_Java_byte_ordering_different(){ return true; }
-
-
// Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering
// (no special code is needed since x86 CPUs can access unaligned data)
static inline u2 get_native_u2(address p) { return *(u2*)p; }
--- a/hotspot/src/cpu/arm/vm/bytes_arm.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/arm/vm/bytes_arm.hpp Fri May 26 13:47:33 2017 -0700
@@ -35,12 +35,6 @@
class Bytes: AllStatic {
public:
- // Returns true if the byte ordering used by Java is different from the native byte ordering
- // of the underlying machine.
- static inline bool is_Java_byte_ordering_different() {
- return VM_LITTLE_ENDIAN != 0;
- }
-
static inline u2 get_Java_u2(address p) {
return (u2(p[0]) << 8) | u2(p[1]);
}
--- a/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp Fri May 26 13:47:33 2017 -0700
@@ -37,10 +37,6 @@
#if defined(VM_LITTLE_ENDIAN)
- // Returns true, if the byte ordering used by Java is different from the native byte ordering
- // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
- static inline bool is_Java_byte_ordering_different() { return true; }
-
// Forward declarations of the compiler-dependent implementation
static inline u2 swap_u2(u2 x);
static inline u4 swap_u4(u4 x);
@@ -155,10 +151,6 @@
#else // !defined(VM_LITTLE_ENDIAN)
- // Returns true, if the byte ordering used by Java is different from the nativ byte ordering
- // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
- static inline bool is_Java_byte_ordering_different() { return false; }
-
// Thus, a swap between native and Java ordering is always a no-op:
static inline u2 swap_u2(u2 x) { return x; }
static inline u4 swap_u4(u4 x) { return x; }
--- a/hotspot/src/cpu/s390/vm/bytes_s390.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/s390/vm/bytes_s390.hpp Fri May 26 13:47:33 2017 -0700
@@ -42,12 +42,6 @@
//
// In short, it makes no sense on z/Architecture to piecemeal get or put unaligned data.
- // Returns true if the byte ordering used by Java is different from
- // the native byte ordering of the underlying machine.
- // z/Arch is big endian, thus, a swap between native and Java ordering
- // is always a no-op.
- static inline bool is_Java_byte_ordering_different() { return false; }
-
// Only swap on little endian machines => suffix `_le'.
static inline u2 swap_u2_le(u2 x) { return x; }
static inline u4 swap_u4_le(u4 x) { return x; }
--- a/hotspot/src/cpu/sparc/vm/bytes_sparc.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/sparc/vm/bytes_sparc.hpp Fri May 26 13:47:33 2017 -0700
@@ -34,10 +34,6 @@
// can I count on address always being a pointer to an unsigned char? Yes
- // Returns true, if the byte ordering used by Java is different from the nativ byte ordering
- // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
- static inline bool is_Java_byte_ordering_different() { return false; }
-
// Thus, a swap between native and Java ordering is always a no-op:
static inline u2 swap_u2(u2 x) { return x; }
static inline u4 swap_u4(u4 x) { return x; }
--- a/hotspot/src/cpu/x86/vm/bytes_x86.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/x86/vm/bytes_x86.hpp Fri May 26 13:47:33 2017 -0700
@@ -36,36 +36,85 @@
#endif // AMD64
public:
- // Returns true if the byte ordering used by Java is different from the native byte ordering
- // of the underlying machine. For example, this is true for Intel x86, but false for Solaris
- // on Sparc.
- static inline bool is_Java_byte_ordering_different(){ return true; }
+ // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering
+ template <typename T>
+ static inline T get_native(const void* p) {
+ assert(p != NULL, "null pointer");
+
+ T x;
+ if (is_ptr_aligned(p, sizeof(T))) {
+ x = *(T*)p;
+ } else {
+ memcpy(&x, p, sizeof(T));
+ }
+
+ return x;
+ }
- // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering
- // (no special code is needed since x86 CPUs can access unaligned data)
- static inline u2 get_native_u2(address p) { return *(u2*)p; }
- static inline u4 get_native_u4(address p) { return *(u4*)p; }
- static inline u8 get_native_u8(address p) { return *(u8*)p; }
+ template <typename T>
+ static inline void put_native(void* p, T x) {
+ assert(p != NULL, "null pointer");
- static inline void put_native_u2(address p, u2 x) { *(u2*)p = x; }
- static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; }
- static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; }
+ if (is_ptr_aligned(p, sizeof(T))) {
+ *(T*)p = x;
+ } else {
+ memcpy(p, &x, sizeof(T));
+ }
+ }
+ static inline u2 get_native_u2(address p) { return get_native<u2>((void*)p); }
+ static inline u4 get_native_u4(address p) { return get_native<u4>((void*)p); }
+ static inline u8 get_native_u8(address p) { return get_native<u8>((void*)p); }
+ static inline void put_native_u2(address p, u2 x) { put_native<u2>((void*)p, x); }
+ static inline void put_native_u4(address p, u4 x) { put_native<u4>((void*)p, x); }
+ static inline void put_native_u8(address p, u8 x) { put_native<u8>((void*)p, x); }
// Efficient reading and writing of unaligned unsigned data in Java
// byte ordering (i.e. big-endian ordering). Byte-order reversal is
// needed since x86 CPUs use little-endian format.
- static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); }
- static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); }
- static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); }
+ template <typename T>
+ static inline T get_Java(const address p) {
+ T x = get_native<T>(p);
+
+ if (Endian::is_Java_byte_ordering_different()) {
+ x = swap<T>(x);
+ }
+
+ return x;
+ }
- static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); }
- static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); }
- static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); }
+ template <typename T>
+ static inline void put_Java(address p, T x) {
+ if (Endian::is_Java_byte_ordering_different()) {
+ x = swap<T>(x);
+ }
+ put_native<T>(p, x);
+ }
+
+ static inline u2 get_Java_u2(address p) { return get_Java<u2>(p); }
+ static inline u4 get_Java_u4(address p) { return get_Java<u4>(p); }
+ static inline u8 get_Java_u8(address p) { return get_Java<u8>(p); }
+
+ static inline void put_Java_u2(address p, u2 x) { put_Java<u2>(p, x); }
+ static inline void put_Java_u4(address p, u4 x) { put_Java<u4>(p, x); }
+ static inline void put_Java_u8(address p, u8 x) { put_Java<u8>(p, x); }
// Efficient swapping of byte ordering
+ template <typename T>
+ static T swap(T x) {
+ switch (sizeof(T)) {
+ case sizeof(u1): return x;
+ case sizeof(u2): return swap_u2(x);
+ case sizeof(u4): return swap_u4(x);
+ case sizeof(u8): return swap_u8(x);
+ default:
+ guarantee(false, "invalid size: " SIZE_FORMAT "\n", sizeof(T));
+ return 0;
+ }
+ }
+
static inline u2 swap_u2(u2 x); // compiler-dependent implementation
static inline u4 swap_u4(u4 x); // compiler-dependent implementation
static inline u8 swap_u8(u8 x);
--- a/hotspot/src/cpu/zero/vm/bytes_zero.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/cpu/zero/vm/bytes_zero.hpp Fri May 26 13:47:33 2017 -0700
@@ -36,16 +36,6 @@
class Bytes: AllStatic {
public:
- // Returns true if the byte ordering used by Java is different
- // from the native byte ordering of the underlying machine.
- static inline bool is_Java_byte_ordering_different() {
-#ifdef VM_LITTLE_ENDIAN
- return true;
-#else
- return false;
-#endif
- }
-
// Efficient reading and writing of unaligned unsigned data in
// platform-specific byte ordering.
static inline u2 get_native_u2(address p){
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Fri May 26 13:47:33 2017 -0700
@@ -261,7 +261,7 @@
case JVM_CONSTANT_Utf8 : {
cfs->guarantee_more(2, CHECK); // utf8_length
u2 utf8_length = cfs->get_u2_fast();
- const u1* utf8_buffer = cfs->get_u1_buffer();
+ const u1* utf8_buffer = cfs->current();
assert(utf8_buffer != NULL, "null utf8 buffer");
// Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
@@ -1305,7 +1305,7 @@
"Multiple RuntimeVisibleAnnotations attributes for field in class file %s", CHECK);
}
runtime_visible_annotations_length = attribute_length;
- runtime_visible_annotations = cfs->get_u1_buffer();
+ runtime_visible_annotations = cfs->current();
assert(runtime_visible_annotations != NULL, "null visible annotations");
cfs->guarantee_more(runtime_visible_annotations_length, CHECK);
parse_annotations(cp,
@@ -1323,7 +1323,7 @@
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_annotations_length = attribute_length;
- runtime_invisible_annotations = cfs->get_u1_buffer();
+ runtime_invisible_annotations = cfs->current();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
cfs->skip_u1(attribute_length, CHECK);
@@ -1333,7 +1333,7 @@
"Multiple RuntimeVisibleTypeAnnotations attributes for field in class file %s", CHECK);
}
runtime_visible_type_annotations_length = attribute_length;
- runtime_visible_type_annotations = cfs->get_u1_buffer();
+ runtime_visible_type_annotations = cfs->current();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
@@ -1345,7 +1345,7 @@
}
if (PreserveAllAnnotations) {
runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ runtime_invisible_type_annotations = cfs->current();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(attribute_length, CHECK);
@@ -1699,19 +1699,13 @@
}
-static void copy_u2_with_conversion(u2* dest, const u2* src, int length) {
- while (length-- > 0) {
- *dest++ = Bytes::get_Java_u2((u1*) (src++));
- }
-}
-
-const u2* ClassFileParser::parse_exception_table(const ClassFileStream* const cfs,
- u4 code_length,
- u4 exception_table_length,
- TRAPS) {
+const void* ClassFileParser::parse_exception_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS) {
assert(cfs != NULL, "invariant");
- const u2* const exception_table_start = cfs->get_u2_buffer();
+ const void* const exception_table_start = cfs->current();
assert(exception_table_start != NULL, "null exception table");
cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc,
@@ -1829,13 +1823,13 @@
// Function is used to parse both attributes:
// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
-const u2* ClassFileParser::parse_localvariable_table(const ClassFileStream* cfs,
- u4 code_length,
- u2 max_locals,
- u4 code_attribute_length,
- u2* const localvariable_table_length,
- bool isLVTT,
- TRAPS) {
+const void* ClassFileParser::parse_localvariable_table(const ClassFileStream* cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS) {
const char* const tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable";
*localvariable_table_length = cfs->get_u2(CHECK_NULL);
const unsigned int size =
@@ -1849,7 +1843,7 @@
"%s has wrong length in class file %s", tbl_name, CHECK_NULL);
}
- const u2* const localvariable_table_start = cfs->get_u2_buffer();
+ const void* const localvariable_table_start = cfs->current();
assert(localvariable_table_start != NULL, "null local variable table");
if (!_need_verify) {
cfs->skip_u2_fast(size);
@@ -1953,7 +1947,7 @@
return NULL;
}
- const u1* const stackmap_table_start = cfs->get_u1_buffer();
+ const u1* const stackmap_table_start = cfs->current();
assert(stackmap_table_start != NULL, "null stackmap table");
// check code_attribute_length first
@@ -1965,10 +1959,10 @@
return stackmap_table_start;
}
-const u2* ClassFileParser::parse_checked_exceptions(const ClassFileStream* const cfs,
- u2* const checked_exceptions_length,
- u4 method_attribute_length,
- TRAPS) {
+const void* ClassFileParser::parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS) {
assert(cfs != NULL, "invariant");
assert(checked_exceptions_length != NULL, "invariant");
@@ -1976,7 +1970,7 @@
*checked_exceptions_length = cfs->get_u2_fast();
const unsigned int size =
(*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2);
- const u2* const checked_exceptions_start = cfs->get_u2_buffer();
+ const void* const checked_exceptions_start = cfs->current();
assert(checked_exceptions_start != NULL, "null checked exceptions");
if (!_need_verify) {
cfs->skip_u2_fast(size);
@@ -2143,10 +2137,10 @@
void ClassFileParser::copy_localvariable_table(const ConstMethod* cm,
int lvt_cnt,
u2* const localvariable_table_length,
- const u2**const localvariable_table_start,
+ const void** const localvariable_table_start,
int lvtt_cnt,
u2* const localvariable_type_table_length,
- const u2**const localvariable_type_table_start,
+ const void** const localvariable_type_table_start,
TRAPS) {
ResourceMark rm(THREAD);
@@ -2341,10 +2335,10 @@
u4 code_length = 0;
const u1* code_start = 0;
u2 exception_table_length = 0;
- const u2* exception_table_start = NULL;
+ const void* exception_table_start = NULL; // (potentially unaligned) pointer to array of u2 elements
Array<int>* exception_handlers = Universe::the_empty_int_array();
u2 checked_exceptions_length = 0;
- const u2* checked_exceptions_start = NULL;
+ const void* checked_exceptions_start = NULL; // (potentially unaligned) pointer to array of u2 elements
CompressedLineNumberWriteStream* linenumber_table = NULL;
int linenumber_table_length = 0;
int total_lvt_length = 0;
@@ -2354,9 +2348,9 @@
u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER;
u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER;
u2* localvariable_table_length = NULL;
- const u2** localvariable_table_start = NULL;
+ const void** localvariable_table_start = NULL; // (potentially unaligned) pointer to array of LVT attributes
u2* localvariable_type_table_length = NULL;
- const u2** localvariable_type_table_start = NULL;
+ const void** localvariable_type_table_start = NULL; // (potentially unaligned) pointer to LVTT attributes
int method_parameters_length = -1;
const u1* method_parameters_data = NULL;
bool method_parameters_seen = false;
@@ -2433,7 +2427,7 @@
code_length, CHECK_NULL);
}
// Code pointer
- code_start = cfs->get_u1_buffer();
+ code_start = cfs->current();
assert(code_start != NULL, "null code start");
cfs->guarantee_more(code_length, CHECK_NULL);
cfs->skip_u1_fast(code_length);
@@ -2497,17 +2491,17 @@
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const void*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const void*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
if (lvt_cnt == max_lvt_cnt) {
max_lvt_cnt <<= 1;
localvariable_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt);
- localvariable_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
+ localvariable_table_start = REALLOC_RESOURCE_ARRAY(const void*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
}
localvariable_table_start[lvt_cnt] =
parse_localvariable_table(cfs,
@@ -2526,18 +2520,18 @@
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const void*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const void*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
// Parse local variable type table
if (lvtt_cnt == max_lvtt_cnt) {
max_lvtt_cnt <<= 1;
localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt);
- localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
+ localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const void*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
}
localvariable_type_table_start[lvtt_cnt] =
parse_localvariable_table(cfs,
@@ -2594,7 +2588,7 @@
"Invalid MethodParameters method attribute length %u in class file",
method_attribute_length, CHECK_NULL);
}
- method_parameters_data = cfs->get_u1_buffer();
+ method_parameters_data = cfs->current();
cfs->skip_u2_fast(method_parameters_length);
cfs->skip_u2_fast(method_parameters_length);
// ignore this attribute if it cannot be reflected
@@ -2634,7 +2628,7 @@
CHECK_NULL);
}
runtime_visible_annotations_length = method_attribute_length;
- runtime_visible_annotations = cfs->get_u1_buffer();
+ runtime_visible_annotations = cfs->current();
assert(runtime_visible_annotations != NULL, "null visible annotations");
cfs->guarantee_more(runtime_visible_annotations_length, CHECK_NULL);
parse_annotations(cp,
@@ -2653,7 +2647,7 @@
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_annotations_length = method_attribute_length;
- runtime_invisible_annotations = cfs->get_u1_buffer();
+ runtime_invisible_annotations = cfs->current();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
cfs->skip_u1(method_attribute_length, CHECK_NULL);
@@ -2664,7 +2658,7 @@
CHECK_NULL);
}
runtime_visible_parameter_annotations_length = method_attribute_length;
- runtime_visible_parameter_annotations = cfs->get_u1_buffer();
+ runtime_visible_parameter_annotations = cfs->current();
assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations");
cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
@@ -2676,7 +2670,7 @@
runtime_invisible_parameter_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_parameter_annotations_length = method_attribute_length;
- runtime_invisible_parameter_annotations = cfs->get_u1_buffer();
+ runtime_invisible_parameter_annotations = cfs->current();
assert(runtime_invisible_parameter_annotations != NULL,
"null invisible parameter annotations");
}
@@ -2688,7 +2682,7 @@
CHECK_NULL);
}
annotation_default_length = method_attribute_length;
- annotation_default = cfs->get_u1_buffer();
+ annotation_default = cfs->current();
assert(annotation_default != NULL, "null annotation default");
cfs->skip_u1(annotation_default_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
@@ -2698,7 +2692,7 @@
CHECK_NULL);
}
runtime_visible_type_annotations_length = method_attribute_length;
- runtime_visible_type_annotations = cfs->get_u1_buffer();
+ runtime_visible_type_annotations = cfs->current();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_NULL);
@@ -2712,7 +2706,7 @@
}
if (PreserveAllAnnotations) {
runtime_invisible_type_annotations_length = method_attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ runtime_invisible_type_annotations = cfs->current();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(method_attribute_length, CHECK_NULL);
@@ -2808,10 +2802,10 @@
// Copy exception table
if (exception_table_length > 0) {
- int size =
- exception_table_length * sizeof(ExceptionTableElement) / sizeof(u2);
- copy_u2_with_conversion((u2*) m->exception_table_start(),
- exception_table_start, size);
+ Copy::conjoint_swap_if_needed<Endian::JAVA>(exception_table_start,
+ m->exception_table_start(),
+ exception_table_length * sizeof(ExceptionTableElement),
+ sizeof(u2));
}
// Copy method parameters
@@ -2827,11 +2821,10 @@
// Copy checked exceptions
if (checked_exceptions_length > 0) {
- const int size =
- checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
- copy_u2_with_conversion((u2*) m->checked_exceptions_start(),
- checked_exceptions_start,
- size);
+ Copy::conjoint_swap_if_needed<Endian::JAVA>(checked_exceptions_start,
+ m->checked_exceptions_start(),
+ checked_exceptions_length * sizeof(CheckedExceptionElement),
+ sizeof(u2));
}
// Copy class file LVT's/LVTT's into the HotSpot internal LVT.
@@ -3030,7 +3023,7 @@
TRAPS) {
assert(cfs != NULL, "invariant");
- const u1* const sde_buffer = cfs->get_u1_buffer();
+ const u1* const sde_buffer = cfs->current();
assert(sde_buffer != NULL, "null sde buffer");
// Don't bother storing it if there is no way to retrieve it
@@ -3322,7 +3315,7 @@
} else {
parsed_innerclasses_attribute = true;
}
- inner_classes_attribute_start = cfs->get_u1_buffer();
+ inner_classes_attribute_start = cfs->current();
inner_classes_attribute_length = attribute_length;
cfs->skip_u1(inner_classes_attribute_length, CHECK);
} else if (tag == vmSymbols::tag_synthetic()) {
@@ -3359,7 +3352,7 @@
"Multiple RuntimeVisibleAnnotations attributes in class file %s", CHECK);
}
runtime_visible_annotations_length = attribute_length;
- runtime_visible_annotations = cfs->get_u1_buffer();
+ runtime_visible_annotations = cfs->current();
assert(runtime_visible_annotations != NULL, "null visible annotations");
cfs->guarantee_more(runtime_visible_annotations_length, CHECK);
parse_annotations(cp,
@@ -3377,7 +3370,7 @@
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_annotations_length = attribute_length;
- runtime_invisible_annotations = cfs->get_u1_buffer();
+ runtime_invisible_annotations = cfs->current();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
cfs->skip_u1(attribute_length, CHECK);
@@ -3417,7 +3410,7 @@
"Multiple RuntimeVisibleTypeAnnotations attributes in class file %s", CHECK);
}
runtime_visible_type_annotations_length = attribute_length;
- runtime_visible_type_annotations = cfs->get_u1_buffer();
+ runtime_visible_type_annotations = cfs->current();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
@@ -3430,7 +3423,7 @@
}
if (PreserveAllAnnotations) {
runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ runtime_invisible_type_annotations = cfs->current();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(attribute_length, CHECK);
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Fri May 26 13:47:33 2017 -0700
@@ -242,28 +242,28 @@
bool* const declares_nonstatic_concrete_methods,
TRAPS);
- const u2* parse_exception_table(const ClassFileStream* const stream,
- u4 code_length,
- u4 exception_table_length,
- TRAPS);
+ const void* parse_exception_table(const ClassFileStream* const stream,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS);
void parse_linenumber_table(u4 code_attribute_length,
u4 code_length,
CompressedLineNumberWriteStream**const write_stream,
TRAPS);
- const u2* parse_localvariable_table(const ClassFileStream* const cfs,
- u4 code_length,
- u2 max_locals,
- u4 code_attribute_length,
- u2* const localvariable_table_length,
- bool isLVTT,
- TRAPS);
+ const void* parse_localvariable_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS);
- const u2* parse_checked_exceptions(const ClassFileStream* const cfs,
- u2* const checked_exceptions_length,
- u4 method_attribute_length,
- TRAPS);
+ const void* parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS);
void parse_type_array(u2 array_length,
u4 code_length,
@@ -462,10 +462,10 @@
void copy_localvariable_table(const ConstMethod* cm,
int lvt_cnt,
u2* const localvariable_table_length,
- const u2**const localvariable_table_start,
+ const void** const localvariable_table_start,
int lvtt_cnt,
u2* const localvariable_type_table_length,
- const u2** const localvariable_type_table_start,
+ const void** const localvariable_type_table_start,
TRAPS);
void copy_method_annotations(ConstMethod* cm,
--- a/hotspot/src/share/vm/classfile/classFileStream.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classFileStream.hpp Fri May 26 13:47:33 2017 -0700
@@ -121,17 +121,6 @@
return res;
}
- // Get direct pointer into stream at current position.
- // Returns NULL if length elements are not remaining. The caller is
- // responsible for calling skip below if buffer contents is used.
- const u1* get_u1_buffer() const {
- return _current;
- }
-
- const u2* get_u2_buffer() const {
- return (const u2*) _current;
- }
-
// Skip length u1 or u2 elements from stream
void skip_u1(int length, TRAPS) const;
void skip_u1_fast(int length) const {
--- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Fri May 26 13:47:33 2017 -0700
@@ -249,7 +249,7 @@
return (oop*) slot_addr;
}
static jint* int_addr_in_slot(intptr_t* slot_addr) {
- if ((int) sizeof(jint) < wordSize && !Bytes::is_Java_byte_ordering_different())
+ if ((int) sizeof(jint) < wordSize && !Endian::is_Java_byte_ordering_different())
// big-endian LP64
return (jint*)(slot_addr + 1) - 1;
else
--- a/hotspot/src/share/vm/interpreter/bytecode.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/interpreter/bytecode.hpp Fri May 26 13:47:33 2017 -0700
@@ -122,7 +122,7 @@
static void assert_constant_size(int required_size, int where, Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN;
static void assert_native_index(Bytecodes::Code bc, bool is_wide = false) NOT_DEBUG_RETURN;
static bool can_use_native_byte_order(Bytecodes::Code bc, bool is_wide = false) {
- return (!Bytes::is_Java_byte_ordering_different() || Bytecodes::native_byte_order(bc /*, is_wide*/));
+ return (!Endian::is_Java_byte_ordering_different() || Bytecodes::native_byte_order(bc /*, is_wide*/));
}
};
--- a/hotspot/src/share/vm/services/heapDumper.cpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/services/heapDumper.cpp Fri May 26 13:47:33 2017 -0700
@@ -1134,7 +1134,7 @@
switch (type) {
case T_INT : {
- if (Bytes::is_Java_byte_ordering_different()) {
+ if (Endian::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, int, u4, length);
} else {
writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes);
@@ -1146,7 +1146,7 @@
break;
}
case T_CHAR : {
- if (Bytes::is_Java_byte_ordering_different()) {
+ if (Endian::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, char, u2, length);
} else {
writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes);
@@ -1154,7 +1154,7 @@
break;
}
case T_SHORT : {
- if (Bytes::is_Java_byte_ordering_different()) {
+ if (Endian::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, short, u2, length);
} else {
writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
@@ -1162,7 +1162,7 @@
break;
}
case T_BOOLEAN : {
- if (Bytes::is_Java_byte_ordering_different()) {
+ if (Endian::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, bool, u1, length);
} else {
writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
@@ -1170,7 +1170,7 @@
break;
}
case T_LONG : {
- if (Bytes::is_Java_byte_ordering_different()) {
+ if (Endian::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, long, u8, length);
} else {
writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
--- a/hotspot/src/share/vm/utilities/bytes.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/utilities/bytes.hpp Fri May 26 13:47:33 2017 -0700
@@ -27,6 +27,27 @@
#include "utilities/macros.hpp"
+class Endian : AllStatic {
+public:
+ enum Order {
+ LITTLE,
+ BIG,
+ JAVA = BIG,
+ NATIVE =
+#ifdef VM_LITTLE_ENDIAN
+ LITTLE
+#else
+ BIG
+#endif
+ };
+
+ // Returns true, if the byte ordering used by Java is different from
+ // the native byte ordering of the underlying machine.
+ static inline bool is_Java_byte_ordering_different() {
+ return NATIVE != JAVA;
+ }
+};
+
#include CPU_HEADER(bytes)
#endif // SHARE_VM_UTILITIES_BYTES_HPP
--- a/hotspot/src/share/vm/utilities/copy.cpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/utilities/copy.cpp Fri May 26 13:47:33 2017 -0700
@@ -56,14 +56,17 @@
class CopySwap : AllStatic {
public:
/**
- * Copy and byte swap elements
+ * Copy and optionally byte swap elements
+ *
+ * <swap> - true if elements should be byte swapped
*
* @param src address of source
* @param dst address of destination
* @param byte_count number of bytes to copy
* @param elem_size size of the elements to copy-swap
*/
- static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
+ template<bool swap>
+ static void conjoint_swap_if_needed(const void* src, void* dst, size_t byte_count, size_t elem_size) {
assert(src != NULL, "address must not be NULL");
assert(dst != NULL, "address must not be NULL");
assert(elem_size == 2 || elem_size == 4 || elem_size == 8,
@@ -71,12 +74,12 @@
assert(is_size_aligned(byte_count, elem_size),
"byte_count " SIZE_FORMAT " must be multiple of element size " SIZE_FORMAT, byte_count, elem_size);
- address src_end = src + byte_count;
+ address src_end = (address)src + byte_count;
if (dst <= src || dst >= src_end) {
- do_conjoint_swap<RIGHT>(src, dst, byte_count, elem_size);
+ do_conjoint_swap<RIGHT,swap>(src, dst, byte_count, elem_size);
} else {
- do_conjoint_swap<LEFT>(src, dst, byte_count, elem_size);
+ do_conjoint_swap<LEFT,swap>(src, dst, byte_count, elem_size);
}
}
@@ -125,18 +128,19 @@
* @param dst address of destination
* @param byte_count number of bytes to copy
*/
- template <typename T, CopyDirection D, bool is_src_aligned, bool is_dst_aligned>
- static void do_conjoint_swap(address src, address dst, size_t byte_count) {
- address cur_src, cur_dst;
+ template <typename T, CopyDirection D, bool swap, bool is_src_aligned, bool is_dst_aligned>
+ static void do_conjoint_swap(const void* src, void* dst, size_t byte_count) {
+ const char* cur_src;
+ char* cur_dst;
switch (D) {
case RIGHT:
- cur_src = src;
- cur_dst = dst;
+ cur_src = (const char*)src;
+ cur_dst = (char*)dst;
break;
case LEFT:
- cur_src = src + byte_count - sizeof(T);
- cur_dst = dst + byte_count - sizeof(T);
+ cur_src = (const char*)src + byte_count - sizeof(T);
+ cur_dst = (char*)dst + byte_count - sizeof(T);
break;
}
@@ -149,7 +153,9 @@
memcpy(&tmp, cur_src, sizeof(T));
}
- tmp = byte_swap(tmp);
+ if (swap) {
+ tmp = byte_swap(tmp);
+ }
if (is_dst_aligned) {
*(T*)cur_dst = tmp;
@@ -173,26 +179,27 @@
/**
* Copy and byte swap elements
*
- * <T> - type of element to copy
- * <D> - copy direction
+ * <T> - type of element to copy
+ * <D> - copy direction
+ * <swap> - true if elements should be byte swapped
*
* @param src address of source
* @param dst address of destination
* @param byte_count number of bytes to copy
*/
- template <typename T, CopyDirection direction>
- static void do_conjoint_swap(address src, address dst, size_t byte_count) {
+ template <typename T, CopyDirection direction, bool swap>
+ static void do_conjoint_swap(const void* src, void* dst, size_t byte_count) {
if (is_ptr_aligned(src, sizeof(T))) {
if (is_ptr_aligned(dst, sizeof(T))) {
- do_conjoint_swap<T,direction,true,true>(src, dst, byte_count);
+ do_conjoint_swap<T,direction,swap,true,true>(src, dst, byte_count);
} else {
- do_conjoint_swap<T,direction,true,false>(src, dst, byte_count);
+ do_conjoint_swap<T,direction,swap,true,false>(src, dst, byte_count);
}
} else {
if (is_ptr_aligned(dst, sizeof(T))) {
- do_conjoint_swap<T,direction,false,true>(src, dst, byte_count);
+ do_conjoint_swap<T,direction,swap,false,true>(src, dst, byte_count);
} else {
- do_conjoint_swap<T,direction,false,false>(src, dst, byte_count);
+ do_conjoint_swap<T,direction,swap,false,false>(src, dst, byte_count);
}
}
}
@@ -201,26 +208,31 @@
/**
* Copy and byte swap elements
*
- * <D> - copy direction
+ * <D> - copy direction
+ * <swap> - true if elements should be byte swapped
*
* @param src address of source
* @param dst address of destination
* @param byte_count number of bytes to copy
* @param elem_size size of the elements to copy-swap
*/
- template <CopyDirection D>
- static void do_conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
+ template <CopyDirection D, bool swap>
+ static void do_conjoint_swap(const void* src, void* dst, size_t byte_count, size_t elem_size) {
switch (elem_size) {
- case 2: do_conjoint_swap<uint16_t,D>(src, dst, byte_count); break;
- case 4: do_conjoint_swap<uint32_t,D>(src, dst, byte_count); break;
- case 8: do_conjoint_swap<uint64_t,D>(src, dst, byte_count); break;
+ case 2: do_conjoint_swap<uint16_t,D,swap>(src, dst, byte_count); break;
+ case 4: do_conjoint_swap<uint32_t,D,swap>(src, dst, byte_count); break;
+ case 8: do_conjoint_swap<uint64_t,D,swap>(src, dst, byte_count); break;
default: guarantee(false, "do_conjoint_swap: Invalid elem_size " SIZE_FORMAT "\n", elem_size);
}
}
};
-void Copy::conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
- CopySwap::conjoint_swap(src, dst, byte_count, elem_size);
+void Copy::conjoint_copy(const void* src, void* dst, size_t byte_count, size_t elem_size) {
+ CopySwap::conjoint_swap_if_needed<false>(src, dst, byte_count, elem_size);
+}
+
+void Copy::conjoint_swap(const void* src, void* dst, size_t byte_count, size_t elem_size) {
+ CopySwap::conjoint_swap_if_needed<true>(src, dst, byte_count, elem_size);
}
// Fill bytes; larger units are filled atomically if everything is aligned.
--- a/hotspot/src/share/vm/utilities/copy.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/utilities/copy.hpp Fri May 26 13:47:33 2017 -0700
@@ -229,6 +229,16 @@
}
/**
+ * Copy elements
+ *
+ * @param src address of source
+ * @param dst address of destination
+ * @param byte_count number of bytes to copy
+ * @param elem_size size of the elements to copy-swap
+ */
+ static void conjoint_copy(const void* src, void* dst, size_t byte_count, size_t elem_size);
+
+ /**
* Copy and *unconditionally* byte swap elements
*
* @param src address of source
@@ -236,7 +246,24 @@
* @param byte_count number of bytes to copy
* @param elem_size size of the elements to copy-swap
*/
- static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size);
+ static void conjoint_swap(const void* src, void* dst, size_t byte_count, size_t elem_size);
+
+ /**
+ * Copy and byte swap elements from the specified endian to the native (cpu) endian if needed (if they differ)
+ *
+ * @param src address of source
+ * @param dst address of destination
+ * @param byte_count number of bytes to copy
+ * @param elem_size size of the elements to copy-swap
+ */
+ template <Endian::Order endian>
+ static void conjoint_swap_if_needed(const void* src, void* dst, size_t byte_count, size_t elem_size) {
+ if (Endian::NATIVE != endian) {
+ conjoint_swap(src, dst, byte_count, elem_size);
+ } else {
+ conjoint_copy(src, dst, byte_count, elem_size);
+ }
+ }
// Fill methods
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri May 26 09:48:46 2017 -0400
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri May 26 13:47:33 2017 -0700
@@ -487,7 +487,7 @@
return align_size_up_(size, alignment) == size;
}
-inline bool is_ptr_aligned(void* ptr, size_t alignment) {
+inline bool is_ptr_aligned(const void* ptr, size_t alignment) {
return align_size_up_((intptr_t)ptr, (intptr_t)alignment) == (intptr_t)ptr;
}