8144847: PPC64: Update Transactional Memory and Atomic::cmpxchg code
Reviewed-by: stuefe, goetz
--- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Thu Dec 10 15:27:16 2015 +0100
@@ -36,4 +36,9 @@
// The PPC CPUs are NOT multiple-copy-atomic.
#define CPU_NOT_MULTIPLE_COPY_ATOMIC
+#if defined(COMPILER2) && defined(AIX)
+// Include Transactional Memory lock eliding optimization
+#define INCLUDE_RTM_OPT 1
+#endif
+
#endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP
--- a/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp Thu Dec 10 15:27:16 2015 +0100
@@ -50,12 +50,29 @@
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
+#define __ masm->
+
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
- Unimplemented();
+ intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
+ *(intptr_t *)(*md_top) = vtable_bytes;
+ *md_top += sizeof(intptr_t);
+ void** dummy_vtable = (void**)*md_top;
+ *vtable = dummy_vtable;
+ *md_top += vtable_bytes;
+
+ // Get ready to generate dummy methods.
+
+ CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
+ MacroAssembler* masm = new MacroAssembler(&cb);
+
+ // There are more general problems with CDS on ppc, so I can not
+ // really test this. But having this instead of Unimplementd() allows
+ // us to pass TestOptionsWithRanges.java.
+ __ unimplemented();
}
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Dec 10 15:27:16 2015 +0100
@@ -210,12 +210,27 @@
}
// Adjust RTM (Restricted Transactional Memory) flags.
- if (!has_tcheck() && UseRTMLocking) {
+ if (UseRTMLocking) {
+ // If CPU or OS are too old:
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
// setting during arguments processing. See use_biased_locking().
// VM_Version_init() is executed after UseBiasedLocking is used
// in Thread::allocate().
- vm_exit_during_initialization("RTM instructions are not available on this CPU");
+ if (!has_tcheck()) {
+ vm_exit_during_initialization("RTM instructions are not available on this CPU");
+ }
+ bool os_too_old = true;
+#ifdef AIX
+ if (os::Aix::os_version() >= 0x0701031e) { // at least AIX 7.1.3.30
+ os_too_old = false;
+ }
+#endif
+#ifdef linux
+ // TODO: check kernel version (we currently have too old versions only)
+#endif
+ if (os_too_old) {
+ vm_exit_during_initialization("RTM is not supported on this OS version.");
+ }
}
if (UseRTMLocking) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/libodm_aix.cpp Thu Dec 10 15:27:16 2015 +0100
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "libodm_aix.hpp"
+#include "misc_aix.hpp"
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include "runtime/arguments.hpp"
+
+
+dynamicOdm::dynamicOdm() {
+ const char *libodmname = "/usr/lib/libodm.a(shr_64.o)";
+ _libhandle = dlopen(libodmname, RTLD_MEMBER | RTLD_NOW);
+ if (!_libhandle) {
+ trcVerbose("Couldn't open %s", libodmname);
+ return;
+ }
+ _odm_initialize = (fun_odm_initialize )dlsym(_libhandle, "odm_initialize" );
+ _odm_set_path = (fun_odm_set_path )dlsym(_libhandle, "odm_set_path" );
+ _odm_mount_class = (fun_odm_mount_class)dlsym(_libhandle, "odm_mount_class");
+ _odm_get_obj = (fun_odm_get_obj )dlsym(_libhandle, "odm_get_obj" );
+ _odm_terminate = (fun_odm_terminate )dlsym(_libhandle, "odm_terminate" );
+ if (!_odm_initialize || !_odm_set_path || !_odm_mount_class || !_odm_get_obj || !_odm_terminate) {
+ trcVerbose("Couldn't find all required odm symbols from %s", libodmname);
+ dlclose(_libhandle);
+ _libhandle = NULL;
+ return;
+ }
+}
+
+dynamicOdm::~dynamicOdm() {
+ if (_libhandle) { dlclose(_libhandle); }
+}
+
+
+void odmWrapper::clean_data() { if (_data) { free(_data); _data = NULL; } }
+
+
+int odmWrapper::class_offset(char *field, bool is_aix_5)
+{
+ assert(has_class(), "initialization");
+ for (int i = 0; i < odm_class()->nelem; i++) {
+ if (strcmp(odm_class()->elem[i].elemname, field) == 0) {
+ int offset = odm_class()->elem[i].offset;
+ if (is_aix_5) { offset += LINK_VAL_OFFSET; }
+ return offset;
+ }
+ }
+ return -1;
+}
+
+
+void odmWrapper::determine_os_kernel_version(uint32_t* p_ver) {
+ int major_aix_version = ((*p_ver) >> 24) & 0xFF,
+ minor_aix_version = ((*p_ver) >> 16) & 0xFF;
+ assert(*p_ver, "must be initialized");
+
+ odmWrapper odm("product", "/usr/lib/objrepos"); // could also use "lpp"
+ if (!odm.has_class()) {
+ trcVerbose("try_determine_os_kernel_version: odm init problem");
+ return;
+ }
+ int voff, roff, moff, foff;
+ bool is_aix_5 = (major_aix_version == 5);
+ voff = odm.class_offset("ver", is_aix_5);
+ roff = odm.class_offset("rel", is_aix_5);
+ moff = odm.class_offset("mod", is_aix_5);
+ foff = odm.class_offset("fix", is_aix_5);
+ if (voff == -1 || roff == -1 || moff == -1 || foff == -1) {
+ trcVerbose("try_determine_os_kernel_version: could not get offsets");
+ return;
+ }
+ if (!odm.retrieve_obj("name='bos.mp64'")) {
+ trcVerbose("try_determine_os_kernel_version: odm_get_obj failed");
+ return;
+ }
+ int version, release, modification, fix_level;
+ do {
+ version = odm.read_short(voff);
+ release = odm.read_short(roff);
+ modification = odm.read_short(moff);
+ fix_level = odm.read_short(foff);
+ trcVerbose("odm found version: %d.%d.%d.%d", version, release, modification, fix_level);
+ if (version >> 8 != 0 || release >> 8 != 0 || modification >> 8 != 0 || fix_level >> 8 != 0) {
+ trcVerbose("8 bit numbers expected");
+ return;
+ }
+ } while (odm.retrieve_obj());
+
+ if (version != major_aix_version || release != minor_aix_version) {
+ trcVerbose("version determined by odm does not match uname");
+ return;
+ }
+ *p_ver = version << 24 | release << 16 | modification << 8 | fix_level;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/libodm_aix.hpp Thu Dec 10 15:27:16 2015 +0100
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// Encapsulates the libodm library and provides more convenient interfaces.
+
+#ifndef OS_AIX_VM_LIBODM_AIX_HPP
+#define OS_AIX_VM_LIBODM_AIX_HPP
+
+#include <odmi.h>
+
+
+// The purpose of this code is to dynamically load the libodm library
+// instead of statically linking against it. The library is AIX-specific.
+// It only exists on AIX, not on PASE. In order to share binaries
+// between AIX and PASE, we can't directly link against it.
+
+typedef int (*fun_odm_initialize )(void);
+typedef char* (*fun_odm_set_path )(char*);
+typedef CLASS_SYMBOL (*fun_odm_mount_class)(char*);
+typedef void* (*fun_odm_get_obj )(CLASS_SYMBOL, char*, void*, int);
+typedef int (*fun_odm_terminate )(void);
+
+class dynamicOdm {
+ void *_libhandle;
+ protected:
+ fun_odm_initialize _odm_initialize;
+ fun_odm_set_path _odm_set_path;
+ fun_odm_mount_class _odm_mount_class;
+ fun_odm_get_obj _odm_get_obj;
+ fun_odm_terminate _odm_terminate;
+ public:
+ dynamicOdm();
+ ~dynamicOdm();
+ bool odm_loaded() {return _libhandle != NULL; }
+};
+
+
+// We provide a more convenient interface for odm access and
+// especially to determine the exact AIX kernel version.
+
+class odmWrapper : private dynamicOdm {
+ CLASS_SYMBOL _odm_class;
+ char *_data;
+ bool _initialized;
+ void clean_data();
+
+ public:
+ // Make sure everything gets initialized and cleaned up properly.
+ explicit odmWrapper(char* odm_class_name, char* odm_path = NULL) : _odm_class((CLASS_SYMBOL)-1),
+ _data(NULL), _initialized(false) {
+ if (!odm_loaded()) { return; }
+ _initialized = ((*_odm_initialize)() != -1);
+ if (_initialized) {
+ if (odm_path) { (*_odm_set_path)(odm_path); }
+ _odm_class = (*_odm_mount_class)(odm_class_name);
+ }
+ }
+ ~odmWrapper() {
+ if (_initialized) { (*_odm_terminate)(); clean_data(); }
+ }
+
+ CLASS_SYMBOL odm_class() { return _odm_class; }
+ bool has_class() { return odm_class() != (CLASS_SYMBOL)-1; }
+ int class_offset(char *field, bool is_aix_5);
+ char* data() { return _data; }
+
+ char* retrieve_obj(char* name = NULL) {
+ clean_data();
+ char *cnp = (char*)(void*)(*_odm_get_obj)(odm_class(), name, NULL, (name == NULL) ? ODM_NEXT : ODM_FIRST);
+ if (cnp != (char*)-1) { _data = cnp; }
+ return data();
+ }
+
+ int read_short(int offs) {
+ short *addr = (short*)(data() + offs);
+ return *addr;
+ }
+
+ // Determine the exact AIX kernel version as 4 byte value.
+ // The high order 2 bytes must be initialized already. They can be determined by uname.
+ static void determine_os_kernel_version(uint32_t* p_ver);
+};
+
+#endif // OS_AIX_VM_LIBODM_AIX_HPP
--- a/hotspot/src/os/aix/vm/os_aix.cpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Thu Dec 10 15:27:16 2015 +0100
@@ -38,6 +38,7 @@
#include "jvm_aix.h"
#include "libo4.hpp"
#include "libperfstat_aix.hpp"
+#include "libodm_aix.hpp"
#include "loadlib_aix.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
@@ -197,9 +198,13 @@
// -1 = uninitialized, 0 if AIX, 1 if OS/400 pase
int os::Aix::_on_pase = -1;
-// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor
-// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4
-int os::Aix::_os_version = -1;
+// 0 = uninitialized, otherwise 32 bit number:
+// 0xVVRRTTSS
+// VV - major version
+// RR - minor version
+// TT - tech level, if known, 0 otherwise
+// SS - service pack, if known, 0 otherwise
+uint32_t os::Aix::_os_version = 0;
int os::Aix::_stack_page_size = -1;
@@ -358,7 +363,7 @@
// Wrap the function "vmgetinfo" which is not available on older OS releases.
static int checked_vmgetinfo(void *out, int command, int arg) {
- if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) {
guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1");
}
return ::vmgetinfo(out, command, arg);
@@ -367,7 +372,7 @@
// Given an address, returns the size of the page backing that address.
size_t os::Aix::query_pagesize(void* addr) {
- if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) {
// AS/400 older than V6R1: no vmgetinfo here, default to 4K
return SIZE_4K;
}
@@ -1491,6 +1496,10 @@
st->print(name.machine);
st->cr();
+ uint32_t ver = os::Aix::os_version();
+ st->print_cr("AIX kernel version %u.%u.%u.%u",
+ (ver >> 24) & 0xFF, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
+
// rlimit
st->print("rlimit:");
struct rlimit rlim;
@@ -4255,7 +4264,7 @@
// one of Aix::on_pase(), Aix::os_version() static
void os::Aix::initialize_os_info() {
- assert(_on_pase == -1 && _os_version == -1, "already called.");
+ assert(_on_pase == -1 && _os_version == 0, "already called.");
struct utsname uts;
memset(&uts, 0, sizeof(uts));
@@ -4271,28 +4280,34 @@
assert(major > 0, "invalid OS version");
const int minor = atoi(uts.release);
assert(minor > 0, "invalid OS release");
- _os_version = (major << 8) | minor;
+ _os_version = (major << 24) | (minor << 16);
+ char ver_str[20] = {0};
+ char *name_str = "unknown OS";
if (strcmp(uts.sysname, "OS400") == 0) {
// We run on AS/400 PASE. We do not support versions older than V5R4M0.
_on_pase = 1;
- if (_os_version < 0x0504) {
+ if (os_version_short() < 0x0504) {
trcVerbose("OS/400 releases older than V5R4M0 not supported.");
assert(false, "OS/400 release too old.");
- } else {
- trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor);
}
+ name_str = "OS/400 (pase)";
+ jio_snprintf(ver_str, sizeof(ver_str), "%u.%u", major, minor);
} else if (strcmp(uts.sysname, "AIX") == 0) {
// We run on AIX. We do not support versions older than AIX 5.3.
_on_pase = 0;
- if (_os_version < 0x0503) {
+ // Determine detailed AIX version: Version, Release, Modification, Fix Level.
+ odmWrapper::determine_os_kernel_version(&_os_version);
+ if (os_version_short() < 0x0503) {
trcVerbose("AIX release older than AIX 5.3 not supported.");
assert(false, "AIX release too old.");
- } else {
- trcVerbose("We run on AIX %d.%d", major, minor);
}
+ name_str = "AIX";
+ jio_snprintf(ver_str, sizeof(ver_str), "%u.%u.%u.%u",
+ major, minor, (_os_version >> 8) & 0xFF, _os_version & 0xFF);
} else {
- assert(false, "unknown OS");
+ assert(false, name_str);
}
+ trcVerbose("We run on %s %s", name_str, ver_str);
}
guarantee(_on_pase != -1 && _os_version, "Could not determine AIX/OS400 release");
@@ -4357,7 +4372,7 @@
p = ::getenv("LDR_CNTRL");
trcVerbose("LDR_CNTRL=%s.", p ? p : "<unset>");
- if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) {
+ if (os::Aix::on_pase() && os::Aix::os_version_short() == 0x0701) {
if (p && ::strstr(p, "TEXTPSIZE")) {
trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. "
"you may experience hangs or crashes on OS/400 V7R1.");
@@ -5016,7 +5031,7 @@
}
#endif
-bool os::start_debugging(char *buf, int buflen) {
+bool os::start_debugging(char *buf, int buflen) {
int len = (int)strlen(buf);
char *p = &buf[len];
--- a/hotspot/src/os/aix/vm/os_aix.hpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.hpp Thu Dec 10 15:27:16 2015 +0100
@@ -55,15 +55,12 @@
// -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE)
static int _on_pase;
- // -1 = uninitialized, otherwise 16 bit number:
+ // 0 = uninitialized, otherwise 16 bit number:
// lower 8 bit - minor version
// higher 8 bit - major version
// For AIX, e.g. 0x0601 for AIX 6.1
// for OS/400 e.g. 0x0504 for OS/400 V5R4
- static int _os_version;
-
- // 4 Byte kernel version: Version, Release, Tech Level, Service Pack.
- static unsigned int _os_kernel_version;
+ static uint32_t _os_version;
// -1 = uninitialized,
// 0 - SPEC1170 not requested (XPG_SUS_ENV is OFF or not set)
@@ -175,32 +172,31 @@
return _on_pase ? false : true;
}
- // -1 = uninitialized, otherwise 16 bit number:
+ // Get 4 byte AIX kernel version number:
+ // highest 2 bytes: Version, Release
+ // if available: lowest 2 bytes: Tech Level, Service Pack.
+ static uint32_t os_version() {
+ assert(_os_version != 0, "not initialized");
+ return _os_version;
+ }
+
+ // 0 = uninitialized, otherwise 16 bit number:
// lower 8 bit - minor version
// higher 8 bit - major version
// For AIX, e.g. 0x0601 for AIX 6.1
// for OS/400 e.g. 0x0504 for OS/400 V5R4
- static int os_version () {
- assert(_os_version != -1, "not initialized");
- return _os_version;
- }
-
- // Get 4 byte AIX kernel version number:
- // highest 2 bytes: Version, Release
- // if available: lowest 2 bytes: Tech Level, Service Pack.
- static unsigned int os_kernel_version() {
- if (_os_kernel_version) return _os_kernel_version;
- return os_version() << 16;
+ static int os_version_short() {
+ return os_version() >> 16;
}
// Convenience method: returns true if running on PASE V5R4 or older.
static bool on_pase_V5R4_or_older() {
- return on_pase() && os_version() <= 0x0504;
+ return on_pase() && os_version_short() <= 0x0504;
}
// Convenience method: returns true if running on AIX 5.3 or older.
static bool on_aix_53_or_older() {
- return on_aix() && os_version() <= 0x0503;
+ return on_aix() && os_version_short() <= 0x0503;
}
// Returns true if we run in SPEC1170 compliant mode (XPG_SUS_ENV=ON).
--- a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp Thu Dec 10 15:27:16 2015 +0100
@@ -291,6 +291,71 @@
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
}
+#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
+inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
+
+ // Note that cmpxchg guarantees a two-way memory barrier across
+ // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire'
+ // (see atomic.hpp).
+
+ // Using 32 bit internally.
+ volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
+
+#ifdef VM_LITTLE_ENDIAN
+ const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
+#else
+ const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
+#endif
+ const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
+ masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
+ xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
+
+ unsigned int old_value, value32;
+
+ __asm__ __volatile__ (
+ /* fence */
+ strasm_sync
+ /* simple guard */
+ " lbz %[old_value], 0(%[dest]) \n"
+ " cmpw %[masked_compare_val], %[old_value] \n"
+ " bne- 2f \n"
+ /* atomic loop */
+ "1: \n"
+ " lwarx %[value32], 0, %[dest_base] \n"
+ /* extract byte and compare */
+ " srd %[old_value], %[value32], %[shift_amount] \n"
+ " clrldi %[old_value], %[old_value], 56 \n"
+ " cmpw %[masked_compare_val], %[old_value] \n"
+ " bne- 2f \n"
+ /* replace byte and try to store */
+ " xor %[value32], %[xor_value], %[value32] \n"
+ " stwcx. %[value32], 0, %[dest_base] \n"
+ " bne- 1b \n"
+ /* acquire */
+ strasm_sync
+ /* exit */
+ "2: \n"
+ /* out */
+ : [old_value] "=&r" (old_value),
+ [value32] "=&r" (value32),
+ "=m" (*dest),
+ "=m" (*dest_base)
+ /* in */
+ : [dest] "b" (dest),
+ [dest_base] "b" (dest_base),
+ [shift_amount] "r" (shift_amount),
+ [masked_compare_val] "r" (masked_compare_val),
+ [xor_value] "r" (xor_value),
+ "m" (*dest),
+ "m" (*dest_base)
+ /* clobber */
+ : "cc",
+ "memory"
+ );
+
+ return (jbyte)(unsigned char)old_value;
+}
+
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) {
// Note that cmpxchg guarantees a two-way memory barrier across
--- a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp Fri Dec 11 09:08:08 2015 +0100
+++ b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp Thu Dec 10 15:27:16 2015 +0100
@@ -291,6 +291,71 @@
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
}
+#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
+inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
+
+ // Note that cmpxchg guarantees a two-way memory barrier across
+ // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire'
+ // (see atomic.hpp).
+
+ // Using 32 bit internally.
+ volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
+
+#ifdef VM_LITTLE_ENDIAN
+ const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
+#else
+ const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
+#endif
+ const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
+ masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
+ xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
+
+ unsigned int old_value, value32;
+
+ __asm__ __volatile__ (
+ /* fence */
+ strasm_sync
+ /* simple guard */
+ " lbz %[old_value], 0(%[dest]) \n"
+ " cmpw %[masked_compare_val], %[old_value] \n"
+ " bne- 2f \n"
+ /* atomic loop */
+ "1: \n"
+ " lwarx %[value32], 0, %[dest_base] \n"
+ /* extract byte and compare */
+ " srd %[old_value], %[value32], %[shift_amount] \n"
+ " clrldi %[old_value], %[old_value], 56 \n"
+ " cmpw %[masked_compare_val], %[old_value] \n"
+ " bne- 2f \n"
+ /* replace byte and try to store */
+ " xor %[value32], %[xor_value], %[value32] \n"
+ " stwcx. %[value32], 0, %[dest_base] \n"
+ " bne- 1b \n"
+ /* acquire */
+ strasm_sync
+ /* exit */
+ "2: \n"
+ /* out */
+ : [old_value] "=&r" (old_value),
+ [value32] "=&r" (value32),
+ "=m" (*dest),
+ "=m" (*dest_base)
+ /* in */
+ : [dest] "b" (dest),
+ [dest_base] "b" (dest_base),
+ [shift_amount] "r" (shift_amount),
+ [masked_compare_val] "r" (masked_compare_val),
+ [xor_value] "r" (xor_value),
+ "m" (*dest),
+ "m" (*dest_base)
+ /* clobber */
+ : "cc",
+ "memory"
+ );
+
+ return (jbyte)(unsigned char)old_value;
+}
+
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) {
// Note that cmpxchg guarantees a two-way memory barrier across