8180032: Unaligned pointer dereference in ClassFileParser
authormikael
Fri, 26 May 2017 13:47:33 -0700
changeset 46504 38048d4d20e7
parent 46503 760f8f589de3
child 46505 fd4bc78630b1
8180032: Unaligned pointer dereference in ClassFileParser Reviewed-by: dholmes, hseigel
hotspot/src/cpu/aarch64/vm/bytes_aarch64.hpp
hotspot/src/cpu/arm/vm/bytes_arm.hpp
hotspot/src/cpu/ppc/vm/bytes_ppc.hpp
hotspot/src/cpu/s390/vm/bytes_s390.hpp
hotspot/src/cpu/sparc/vm/bytes_sparc.hpp
hotspot/src/cpu/x86/vm/bytes_x86.hpp
hotspot/src/cpu/zero/vm/bytes_zero.hpp
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/classfile/classFileParser.hpp
hotspot/src/share/vm/classfile/classFileStream.hpp
hotspot/src/share/vm/interpreter/abstractInterpreter.hpp
hotspot/src/share/vm/interpreter/bytecode.hpp
hotspot/src/share/vm/services/heapDumper.cpp
hotspot/src/share/vm/utilities/bytes.hpp
hotspot/src/share/vm/utilities/copy.cpp
hotspot/src/share/vm/utilities/copy.hpp
hotspot/src/share/vm/utilities/globalDefinitions.hpp
--- 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;
 }