mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
8144847: PPC64: Update Transactional Memory and Atomic::cmpxchg code
Reviewed-by: stuefe, goetz
This commit is contained in:
parent
97e8a96fe1
commit
faf57db7c8
9 changed files with 440 additions and 38 deletions
|
@ -36,4 +36,9 @@ const int StackAlignmentInBytes = 16;
|
|||
// 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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -210,13 +210,28 @@ void VM_Version::initialize() {
|
|||
}
|
||||
|
||||
// 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().
|
||||
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) {
|
||||
#if INCLUDE_RTM_OPT
|
||||
|
|
118
hotspot/src/os/aix/vm/libodm_aix.cpp
Normal file
118
hotspot/src/os/aix/vm/libodm_aix.cpp
Normal file
|
@ -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;
|
||||
}
|
106
hotspot/src/os/aix/vm/libodm_aix.hpp
Normal file
106
hotspot/src/os/aix/vm/libodm_aix.hpp
Normal file
|
@ -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
|
|
@ -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 @@ int os::Aix::_page_size = -1;
|
|||
// -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 @@ static char cpu_arch[] = "ppc64";
|
|||
|
||||
// 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 @@ static int checked_vmgetinfo(void *out, int command, int arg) {
|
|||
// 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 @@ void os::print_os_info(outputStream* st) {
|
|||
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 @@ bool os::Aix::is_primordial_thread() {
|
|||
// 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 @@ void os::Aix::initialize_os_info() {
|
|||
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 @@ void os::Aix::scan_environment() {
|
|||
|
||||
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 @@ void TestReserveMemorySpecial_test() {
|
|||
}
|
||||
#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];
|
||||
|
||||
|
|
|
@ -55,15 +55,12 @@ class Aix {
|
|||
// -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 @@ class Aix {
|
|||
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).
|
||||
|
|
|
@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
|
|||
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
|
||||
|
|
|
@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
|
|||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue