changeset 8067:d82a138c4129

8163469: aarch32: add support for ARMv6K CPU Reviewed-by: duke Contributed-by: andrey.petushkov@gmail.com
author snazarki
date Mon, 15 Aug 2016 12:51:22 +0300
parents 36fd104e90c5
children 11c16b05e869
files src/cpu/aarch32/vm/assembler_aarch32.cpp src/cpu/aarch32/vm/assembler_aarch32.hpp src/cpu/aarch32/vm/interp_masm_aarch32.cpp src/cpu/aarch32/vm/macroAssembler_aarch32.cpp src/cpu/aarch32/vm/macroAssembler_aarch32.hpp src/cpu/aarch32/vm/nativeInst_aarch32.cpp src/cpu/aarch32/vm/nativeInst_aarch32.hpp src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp src/cpu/aarch32/vm/stubGenerator_aarch32.cpp src/cpu/aarch32/vm/vm_version_aarch32.cpp src/cpu/aarch32/vm/vm_version_aarch32.hpp src/os_cpu/linux_aarch32/vm/atomic_linux_aarch32.inline.hpp src/os_cpu/linux_aarch32/vm/os_linux_aarch32.cpp
diffstat 13 files changed, 162 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/aarch32/vm/assembler_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/assembler_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -61,12 +61,16 @@
   //   printf("\n");
   // }
 
+#ifdef ASSERT
   Assembler _masm(cb);
   address entry = __ pc();
 
   // Smoke test for assembler
+  // we're checking the code generation, not applicability of the code to the actual target
+  // so temporarily override the detected cpu to allow emission of all instructions
+  const ProcessorFeatures detected_features = VM_Version::features();
+  VM_Version::features(FT_ALL);
 
-#ifdef ASSERT
 // BEGIN  Generated code -- do not edit
 // Generated by aarch32-asmtest.py
     Label back, forth, near, near_post, near_flt, near_post_flt;
@@ -1203,6 +1207,10 @@
     0xe120017a,
   };
 // END  Generated code -- do not edit
+
+  // reset the detected cpu feature set
+  VM_Version::features(detected_features);
+
   {
     bool ok = true;
     unsigned int *insns1 = (unsigned int *)entry;
@@ -1408,7 +1416,6 @@
   }
 }
 
-
 bool Address::offset_ok_for_immed(long offset, InsnDataType type) {
   const int o = offset < 0 ? -offset : offset;
   switch (type) {
--- a/src/cpu/aarch32/vm/assembler_aarch32.hpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/assembler_aarch32.hpp	Mon Aug 15 12:51:22 2016 +0300
@@ -28,6 +28,7 @@
 #define CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP
 
 #include "asm/register.hpp"
+#include "vm_version_aarch32.hpp"
 
 // Definitions of various symbolic names for machine registers
 
@@ -619,6 +620,8 @@
 
   enum { instruction_size = 4 };
 
+  static const uint32_t nop_insn = 0xe1a00000;
+
   Address adjust(Register base, int offset, bool preIncrement) {
     if (preIncrement)
       return Address(base, offset, Address::pre);
@@ -1416,6 +1419,7 @@
 #undef INSN
 
 void bfi(Register Rd, Register Rn, int lsb, int width, Condition cond = C_DFLT) {
+  assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu");
   int msb = lsb + width - 1;
   assert(lsb >= 0 && lsb < 32, "lsb out of range");
   assert(msb < 32 && msb >= lsb, "width out of range");
@@ -1425,6 +1429,7 @@
 }
 
 void bfc(Register Rd, int lsb, int width, Condition cond = C_DFLT) {
+  assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu");
   int msb = lsb + width - 1;
   assert(lsb >= 0 && lsb < 32, "lsb out of range");
   assert(msb < 32 && msb >= lsb, "width out of range");
--- a/src/cpu/aarch32/vm/interp_masm_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/interp_masm_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -61,12 +61,12 @@
   andr(result, result, 0x1, Assembler::EQ);
 
   cmp(rscratch1, T_BYTE);
-  sbfx(result, result, 0, 8, Assembler::EQ);
+  sxtb(result, result, Assembler::ror(), Assembler::EQ);
 
   cmp(rscratch1, T_CHAR);
-  ubfx(result, result, 0, 16, Assembler::EQ);  // truncate upper 16 bits
+  uxth(result, result, Assembler::ror(), Assembler::EQ);  // truncate upper 16 bits
 
-  sbfx(result, result, 0, 16, Assembler::NE);  // sign-extend short
+  sxth(result, result, Assembler::ror(), Assembler::NE);  // sign-extend short
 
   // Nothing to do for T_INT
   bind(done);
--- a/src/cpu/aarch32/vm/macroAssembler_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/macroAssembler_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -171,11 +171,10 @@
       assert(nativeInstruction_at(&insn_buf[2])->is_orr(), "wrong insns in patch");
       assert(nativeInstruction_at(&insn_buf[3])->is_orr(), "wrong insns in patch");
       u_int32_t addr;
-      // TODO Check that the rotations are in the expected order.
-      addr  = Instruction_aarch32::extract(insn_buf[0], 7, 0) << 0;
-      addr |= Instruction_aarch32::extract(insn_buf[1], 7, 0) << 8;
-      addr |= Instruction_aarch32::extract(insn_buf[2], 7, 0) << 16;
-      addr |= Instruction_aarch32::extract(insn_buf[3], 7, 0) << 24;
+      addr  = Assembler::decode_imm12(Instruction_aarch32::extract(insn_buf[0], 11, 0));
+      addr |= Assembler::decode_imm12(Instruction_aarch32::extract(insn_buf[1], 11, 0));
+      addr |= Assembler::decode_imm12(Instruction_aarch32::extract(insn_buf[2], 11, 0));
+      addr |= Assembler::decode_imm12(Instruction_aarch32::extract(insn_buf[3], 11, 0));
       return address(addr);
     } else {
       ShouldNotReachHere();
@@ -627,9 +626,12 @@
 
   // Have make trampline such way: destination address should be raw 4 byte value,
   // so it's patching could be done atomically.
-  add(lr, r15_pc, 4); // pc is this addr + 8
+  add(lr, r15_pc, NativeCall::instruction_size - 2 * NativeInstruction::arm_insn_sz);
   ldr(r15_pc, Address(r15_pc, 4)); // Address does correction for offset from pc base
   emit_int32((uintptr_t) entry.target());
+  // possibly pad the call to the NativeCall size to make patching happy
+  for (int i = NativeCall::instruction_size; i > 3 * NativeInstruction::arm_insn_sz; i -= NativeInstruction::arm_insn_sz)
+    nop();
 }
 
 void MacroAssembler::ic_call(address entry) {
@@ -3226,3 +3228,22 @@
   BIND(L_exit);
     inv(crc, crc);
 }
+
+void MacroAssembler::bfc_impl(Register Rd, int lsb, int width, Condition cond) {
+  if (width > 15 && lsb == 0) {
+    lsr(Rd, Rd, width);
+    lsl(Rd, Rd, width);
+  } else if (width > 15 && lsb + width == 32) {
+    lsl(Rd, Rd, 32 - lsb);
+    lsr(Rd, Rd, 32 - lsb);
+  } else {
+    const int lsb1 = (lsb & 1);
+    int w1 = width <= 8 - lsb1 ? width : 8 - lsb1;
+    while (width) {
+      bic(Rd, Rd, ((1 << w1) - 1) << lsb);
+      width -= w1;
+      lsb += w1;
+      w1 = width > 8 ? 8 : width;
+    }
+  }
+}
--- a/src/cpu/aarch32/vm/macroAssembler_aarch32.hpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/macroAssembler_aarch32.hpp	Mon Aug 15 12:51:22 2016 +0300
@@ -799,10 +799,19 @@
   using Assembler::strd;
   int strd(Register Rt, Register Rt2, const Address& adr, Condition cond = C_DFLT);
 
+private:
+  void bfc_impl(Register rd, int lsb, int width, Condition cond);
+public:
+  void bfc(Register Rd, int lsb, int width, Condition cond = C_DFLT) {
+    if (VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7))
+      Assembler::bfc(Rd, lsb, width, cond);
+    else
+      bfc_impl(Rd, lsb, width, cond);
+  }
+
   void align_stack() {
-    // sp &= ~StackAlignmentInBytes, assuming it's the power of 2
     if (StackAlignmentInBytes > 4)
-      bfc(sp, 0, __builtin_ctz(StackAlignmentInBytes));
+      bic(sp, sp, StackAlignmentInBytes-1);
   }
 
 #ifdef ASSERT
--- a/src/cpu/aarch32/vm/nativeInst_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/nativeInst_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -39,7 +39,8 @@
 #endif
 
 // LIRAssembler fills patching site with nops up to NativeCall::instruction_size
-static const int patching_copy_buff_len = NativeCall::instruction_size;
+int NativeCall::instruction_size = 5 * arm_insn_sz;
+#define patching_copy_buff_len (NativeCall::instruction_size)
 
 NativeInstruction* NativeInstruction::from(address addr) {
   return (NativeInstruction*) addr;
@@ -47,6 +48,10 @@
 
 //-------------------------------------------------------------------
 
+void NativeCall::init() {
+  instruction_size = (VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7) ? 3 : 5) * arm_insn_sz;
+}
+
 void NativeCall::verify() {
   if (!is_call()) {
     fatal("not a call");
@@ -166,8 +171,8 @@
 }
 
 bool NativeTrampolineCall::is_at(address addr) {
-  return as_uint(addr    ) == 0xe28fe004    // add     lr, pc, #4
-      && as_uint(addr + 4) == 0xe51ff004;   // ldr     pc, [pc, -4]
+  return (as_uint(addr    ) & ~0xffu) == 0xe28fe000  // add     lr, pc, #disp
+       && as_uint(addr + 4)          == 0xe51ff004; // ldr     pc, [pc, -4]
 }
 
 NativeTrampolineCall* NativeTrampolineCall::from(address addr) {
@@ -266,11 +271,18 @@
   return (Instruction_aarch32::extract(insn, 27, 16) & 0b111001011111) == 0b010000011111;
 }
 
-bool NativeMovConstReg::is_at(address addr) {
-  return NativeMovConstReg::is_movw_movt_at(addr) ||
-    NativeMovConstReg::is_ldr_literal_at(addr);
+bool NativeMovConstReg::is_mov_n_three_orr_at(address addr) {
+  return (Instruction_aarch32::extract(as_uint(addr), 27, 16) & 0b111111101111) == 0b001110100000 &&
+          Instruction_aarch32::extract(as_uint(addr+arm_insn_sz), 27, 20) == 0b00111000 &&
+          Instruction_aarch32::extract(as_uint(addr+2*arm_insn_sz), 27, 20) == 0b00111000 &&
+          Instruction_aarch32::extract(as_uint(addr+3*arm_insn_sz), 27, 21) == 0b0011100;
 }
 
+bool NativeMovConstReg::is_at(address addr) {
+  return is_ldr_literal_at(addr) ||
+          is_movw_movt_at(addr) ||
+          is_mov_n_three_orr_at(addr);
+}
 
 //-------------------------------------------------------------------
 // TODO review
--- a/src/cpu/aarch32/vm/nativeInst_aarch32.hpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/nativeInst_aarch32.hpp	Mon Aug 15 12:51:22 2016 +0300
@@ -158,11 +158,13 @@
  protected:
   static bool is_movw_movt_at(address instr);
   static bool is_ldr_literal_at(address instr);
+  static bool is_mov_n_three_orr_at(address instr);
  public:
   enum {
     movw_movt_pair_sz = 2 * arm_insn_sz,
+    mov_n_three_orr_sz = 4 * arm_insn_sz,
     ldr_sz = arm_insn_sz,
-    max_instruction_size = movw_movt_pair_sz,
+    max_instruction_size = mov_n_three_orr_sz,
     min_instruction_size = ldr_sz,
   };
 
@@ -171,6 +173,8 @@
       return addr() + movw_movt_pair_sz;
     } else if (is_ldr_literal_at(addr())) {
       return addr() + ldr_sz;
+    } else if (is_mov_n_three_orr_at(addr())) {
+      return addr() + mov_n_three_orr_sz;
     }
 
     // Unknown instruction in NativeMovConstReg
@@ -207,23 +211,6 @@
   return NativeMovConstReg::from(address);
 }
 
-inline NativeMovConstReg* nativeMovConstReg_before(address addr) {
-  address mov_addr = NULL;
-  if (NativeMovConstReg::is_movw_movt_at(addr - NativeMovConstReg::movw_movt_pair_sz)) {
-    mov_addr = addr - NativeMovConstReg::movw_movt_pair_sz;
-  } else if (NativeMovConstReg::is_ldr_literal_at(addr - NativeMovConstReg::ldr_sz)) {
-    mov_addr = addr - NativeMovConstReg::ldr_sz;
-  } else {
-    ShouldNotReachHere();
-  }
-
-  NativeMovConstReg* test = (NativeMovConstReg*) mov_addr;
-#ifdef ASSERT
-  test->verify();
-#endif
-  return test;
-}
-
 class NativeTrampolineCall: public NativeBranchType {
  public:
   enum {
@@ -236,10 +223,7 @@
   static bool is_at(address address);
   static NativeTrampolineCall* from(address address);
 
-  address next_instruction_address() const  {
-    assert(is_at(addr()), "not call");
-    return addr() + instruction_size;
-  }
+  address next_instruction_address() const;
 };
 
 class NativeRegCall: public NativeBranchType {
@@ -263,17 +247,22 @@
   //  NativeTrampolineCall
  public:
   enum {
-    instruction_size = 3 * arm_insn_sz
+    max_instruction_size = 5 * arm_insn_sz
   };
+
+  static int instruction_size;
 #ifdef ASSERT
-  StaticAssert<(int) NativeTrampolineCall::instruction_size <= (int) instruction_size> dummy1;
+  StaticAssert<(int) NativeTrampolineCall::instruction_size <= (int) max_instruction_size> dummy1;
   StaticAssert<NativeMovConstReg::movw_movt_pair_sz
-      + NativeRegCall::instruction_size <= (int) instruction_size> dummy2;
+      + NativeRegCall::instruction_size <= (int) max_instruction_size> dummy2;
+  StaticAssert<NativeMovConstReg::mov_n_three_orr_sz
+      + NativeRegCall::instruction_size <= (int) max_instruction_size> dummy3;
 #endif
 
   address destination() const;
   void set_destination(address dest);
 
+  static void init();
   void  verify_alignment()                       { ; }
   void  verify();
   void  print();
@@ -306,6 +295,11 @@
   static bool is_call_before(address return_address);
 };
 
+inline address NativeTrampolineCall::next_instruction_address() const {
+  assert(is_at(addr()), "not call");
+  return addr() + NativeCall::instruction_size;
+}
+
 inline NativeCall* nativeCall_at(address address) {
   return NativeCall::from(address);
 }
--- a/src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/sharedRuntime_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -99,7 +99,7 @@
       r10_off, rmethod_off = r10_off,
       r11_off,
       r12_off,
-          reg_save_pad, // align area to 8-bytes to simplify stack alignment to 8
+      reg_save_pad, // align area to 8-bytes to simplify stack alignment to 8
       rfp_off,
       return_off,
       reg_save_size,
--- a/src/cpu/aarch32/vm/stubGenerator_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/stubGenerator_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -1322,6 +1322,8 @@
       StubRoutines::_crc_table_adr = (address)StubRoutines::aarch32::_crc_table;
       StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
     }
+
+    NativeCall::init();
   }
 
   void generate_all() {
--- a/src/cpu/aarch32/vm/vm_version_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/vm_version_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -34,103 +34,20 @@
 #ifdef TARGET_OS_FAMILY_linux
 # include "os_linux.inline.hpp"
 #endif
-
-#ifndef AT_HWCAP
-#define AT_HWCAP        16              /* Machine-dependent hints about
-                                           processor capabilities.  */
-#endif
-
-#ifndef AT_HWCAP2
-#define AT_HWCAP2       26              /* More machine-dependent hints about
-                                           processor capabilities.  */
-#endif
-
-#ifndef HWCAP2_PMULL
-#define HWCAP2_PMULL    (1 << 1)
-#endif
-
-#ifndef HWCAP2_AES
-#define HWCAP2_AES      (1 << 0)
-#endif
-
-#ifndef HWCAP2_SHA1
-#define HWCAP2_SHA1     (1 << 2)
-#endif
-
-#ifndef HWCAP2_SHA2
-#define HWCAP2_SHA2     (1 << 3)
-#endif
-
-#ifndef HWCAP2_CRC32
-#define HWCAP2_CRC32    (1 << 4)
-#endif
-
-#ifndef HWCAP_NEON
-#define HWCAP_NEON      (1 << 12)
-#endif
-
-#ifndef HWCAP_VFPv3
-#define HWCAP_VFPv3     (1 << 13)
-#endif
-
-#ifndef HWCAP_VFPv3D16
-#define HWCAP_VFPv3D16  (1 << 14)       /* also set for VFPv4-D16 */
-#endif
-
-#ifndef HWCAP_TLS
-#define HWCAP_TLS       (1 << 15)
-#endif
-
-#ifndef HWCAP_VFPv4
-#define HWCAP_VFPv4     (1 << 16)
-#endif
-
-#ifndef HWCAP_IDIVA
-#define HWCAP_IDIVA     (1 << 17)
-#endif
-
-#ifndef HWCAP_VFPD32
-#define HWCAP_VFPD32    (1 << 19)       /* set if VFP has 32 regs (not 16) */
-#endif
+#include "compiler/disassembler.hpp"
 
 enum ProcessorFeatures VM_Version::_features = FT_NONE;
 const char* VM_Version::_cpu_features = "";
 
 static BufferBlob* stub_blob;
 static const int stub_size = 550;
+volatile bool VM_Version::_is_determine_features_test_running = false;
 
 extern "C" {
   typedef void (*getPsrInfo_stub_t)(void*);
 }
 static getPsrInfo_stub_t getPsrInfo_stub = NULL;
 
-typedef unsigned long (*pgetauxval)(unsigned long type);
-
-class VM_Version_StubGenerator: public StubCodeGenerator {
- public:
-
-  VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
-
-  address generate_getPsrInfo() {
-    StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub");
-#   define __ _masm->
-    address start = __ pc();
-
-    // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info);
-
-    address entry = __ pc();
-
-    // TODO : redefine fields in CpuidInfo and generate
-    // code to fill them in
-
-    __ b(lr);
-
-#   undef __
-
-    return start;
-  }
-};
-
 
 bool VM_Version::identify_procline(const char *tag, char **line) {
   char *i = *line;
@@ -165,87 +82,59 @@
 
   enum ProcessorFeatures f = FT_NONE;
 
-  // try the recommended way, by using glibc API.
-  // however since this API is only available in recent
-  // versions of glibc we got to invoke it indirectly for
-  // not to create compile and run-time dependency
-  pgetauxval getauxval_ptr = (pgetauxval) os::dll_lookup((void*) 0, "getauxval");
-  if (getauxval_ptr) {
-    unsigned long auxv2 = (*getauxval_ptr)(AT_HWCAP2);
-    unsigned long auxv = (*getauxval_ptr)(AT_HWCAP);
-    if (FLAG_IS_DEFAULT(UseCRC32)) {
-      UseCRC32 = (auxv2 & HWCAP2_CRC32) != 0;
-    }
-    if (auxv2 & HWCAP2_AES) {
-      UseAES = UseAES || FLAG_IS_DEFAULT(UseAES);
-      UseAESIntrinsics =
-              UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics));
-      if (UseAESIntrinsics && !UseAES) {
-        warning("UseAESIntrinsics enabled, but UseAES not, enabling");
-        UseAES = true;
-      }
-    } else {
-      if (UseAES) {
-        warning("UseAES specified, but not supported on this CPU");
-      }
-      if (UseAESIntrinsics) {
-        warning("UseAESIntrinsics specified, but not supported on this CPU");
-      }
-    }
-    if (auxv & HWCAP_NEON)
-      f = (ProcessorFeatures) (f | FT_AdvSIMD);
-    if (auxv & HWCAP_IDIVA)
-      f = (ProcessorFeatures) (f | FT_HW_DIVIDE);
-    if (auxv & HWCAP_VFPv3)
-      f = (ProcessorFeatures) (f | FT_VFPV3 | FT_VFPV2);
-    if (auxv2 & HWCAP2_CRC32)
-      f = (ProcessorFeatures) (f | FT_CRC32);
+  // Allocate space for the code.
+  const int code_size = 10 * Assembler::instruction_size;
+  ResourceMark rm;
+  CodeBuffer cb("detect_cpu_features", code_size, 0);
+  MacroAssembler* a = new MacroAssembler(&cb);
+  jlong test_area;
+
+  // Must be set to true so we can generate the test code.
+  _features = FT_ALL;
+  // Emit code.
+  uint32_t *const code = (uint32_t *)a->pc();
+  void (*test)(address addr, uintptr_t offset)=(void(*)(address addr, uintptr_t nonzero))(void *)code;
+
+  a->udiv(r3, r2, r1);     // FT_HW_DIVIDE
+  a->bfc(r1, 1, 1);        // FT_ARMV6T2
+  a->vneg_f64(d0, d0);     // FT_VFPV2
+  a->vmov_f64(d0, 1.);     // FT_VFPV3
+  a->dmb(Assembler::ISH);  // FT_ARMV7
+  a->ldrexd(r2, r0);       // FT_ARMV6K
+  a->vmov_f64(d0, 0.0);    // FT_AdvSIMD
+  a->crc32b(r3, r2, r1);   // FT_CRC32
+  a->b(lr);
+
+  uint32_t *const code_end = (uint32_t *)a->pc();
+  a->flush();
+  _features = FT_NONE;
+
+  // Print the detection code.
+  if (PrintAssembly) {
+    ttyLocker ttyl;
+    tty->print_cr("Decoding cpu-feature detection stub at " INTPTR_FORMAT " before execution:", p2i(code));
+    Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
   }
+  // Execute code. Illegal instructions will be replaced by 0 in the signal handler.
+  VM_Version::_is_determine_features_test_running = true;
+  (*test)((address)&test_area, 1);
+  VM_Version::_is_determine_features_test_running = false;
+
+  uint32_t *insn = code;
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_HW_DIVIDE);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV6T2);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_VFPV2);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_VFPV3);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV7);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_ARMV6K);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_AdvSIMD);
+  if (*insn++ != Assembler::nop_insn) f = (ProcessorFeatures) (f | FT_CRC32);
 
   int ncores = 0, cpu, variant, model, revision;
   char buf[2048], *i;
   if (FILE * fp = fopen("/proc/cpuinfo", "r")) {
     while ((i = fgets(buf, 2048, fp))) {
-      if (identify_procline("Features", &i)) {
-        i = strtok(i, " \n");
-        while (i) {
-          if (!strcmp("idiva", i)) {
-            f = (ProcessorFeatures) (f | FT_HW_DIVIDE);
-          } else if (!strcmp("vfpv3", i) || !strcmp("vfpv4", i)) {
-            // Assuming that vfpv4 implements all of vfpv3
-            // and that they both implement all of v2.
-            f = (ProcessorFeatures) (f | FT_VFPV3 | FT_VFPV2);
-          } else if (!strcmp("vfp", i)) {
-            // Assuming that VFPv2 is identified by plain vfp
-            f = (ProcessorFeatures) (f | FT_VFPV2);
-          } else if (!strcmp("neon", i)) {
-            f = (ProcessorFeatures) (f | FT_AdvSIMD);
-          }
-          i = strtok(NULL, " \n");
-        }
-      } else if (identify_procline("Processor", &i)) {
-        i = strtok(i, " \n");
-        while (i) {
-          // if the info is read correctly do
-          if (!strcmp("ARMv7", i)) {
-            f = (ProcessorFeatures) (f | FT_ARMV7);
-          } else if (!strcmp("ARMv6-compatible", i)) {
-            //TODO sort out the ARMv6 identification code
-          }
-          i = strtok(NULL, " \n");
-        }
-      } else if (identify_procline("model name", &i)) {
-        i = strtok(i, " \n");
-        while (i) {
-          // if the info is read correctly do
-          if (!strcmp("ARMv7", i) || !strcmp("AArch64", i)) {
-            f = (ProcessorFeatures) (f | FT_ARMV7);
-          } else if (!strcmp("ARMv6-compatible", i)) {
-            //TODO sort out the ARMv6 identification code
-          }
-          i = strtok(NULL, " \n");
-        }
-      } else if (identify_procline("processor", &i)) {
+      if (identify_procline("processor", &i)) {
         ncores++;
       } else if (identify_procline("CPU implementer", &i)) {
         cpu = strtol(i, NULL, 0);
@@ -326,11 +215,6 @@
     vm_exit_during_initialization("Unable to allocate getPsrInfo_stub");
   }
 
-  CodeBuffer c(stub_blob);
-  VM_Version_StubGenerator g(&c);
-  getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t,
-                                   g.generate_getPsrInfo());
-
   get_processor_features();
 
   //FIXME: turning off CriticalJNINatives flag while it is not implemented
--- a/src/cpu/aarch32/vm/vm_version_aarch32.hpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/cpu/aarch32/vm/vm_version_aarch32.hpp	Mon Aug 15 12:51:22 2016 +0300
@@ -41,6 +41,7 @@
   FT_SINGLE_CORE = 64,
   FT_AdvSIMD = 128,
   FT_CRC32 = 256,
+  FT_ALL = 0xffff
 };
 
 class VM_Version : public Abstract_VM_Version {
@@ -67,6 +68,7 @@
  private:
   static enum ProcessorFeatures _features;
   static const char* _cpu_features;
+    static volatile bool _is_determine_features_test_running;
 
   static void get_processor_features();
   static bool identify_procline(const char *tag, char **line);
@@ -75,7 +77,12 @@
   static enum ProcessorFeatures features() {
     return _features;
   }
+    static void features(ProcessorFeatures f) {
+      _features = f;
+    }
   static const char* cpu_features() { return _cpu_features; }
+
+    static bool is_determine_features_test_running() { return _is_determine_features_test_running; }
 };
 
 #endif // CPU_AARCH32_VM_VM_VERSION_AARCH32_HPP
--- a/src/os_cpu/linux_aarch32/vm/atomic_linux_aarch32.inline.hpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/os_cpu/linux_aarch32/vm/atomic_linux_aarch32.inline.hpp	Mon Aug 15 12:51:22 2016 +0300
@@ -33,9 +33,15 @@
 
 // Implementation of class atomic
 
+#if defined(__ARM_ARCH) && __ARM_ARCH >= 7
+#define FULL_MEM_BARRIER  __asm__ __volatile__ ("dmb ish"   : : : "memory")
+#define READ_MEM_BARRIER  __asm__ __volatile__ ("dmb ish"   : : : "memory")
+#define WRITE_MEM_BARRIER __asm__ __volatile__ ("dmb ishst" : : : "memory")
+#else
 #define FULL_MEM_BARRIER  __sync_synchronize()
 #define READ_MEM_BARRIER  __atomic_thread_fence(__ATOMIC_ACQUIRE);
 #define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE);
+#endif
 
 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
 inline void Atomic::store    (jshort   store_value, jshort*   dest) { *dest = store_value; }
--- a/src/os_cpu/linux_aarch32/vm/os_linux_aarch32.cpp	Fri Aug 12 18:10:58 2016 +0300
+++ b/src/os_cpu/linux_aarch32/vm/os_linux_aarch32.cpp	Mon Aug 15 12:51:22 2016 +0300
@@ -375,6 +375,11 @@
           // Determination of interpreter/vtable stub/compiled code null exception
           stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
       }
+    } else if (sig == SIGILL && VM_Version::is_determine_features_test_running()) {
+        // SIGILL must be caused by VM_Version::get_processor_features().
+        *(int *)pc = Assembler::nop_insn; // patch instruction to NOP to indicate that it causes a SIGILL,
+                        // flushing of icache is not necessary.
+        stub = pc + 4;  // continue with next instruction.
     } else if (thread->thread_state() == _thread_in_vm &&
                sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
                thread->doing_unsafe_access()) {