diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp	2023-04-16 11:42:17.119361148 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
+
+// Implementation of class atomic
+
+// Implement ADD using a CAS loop.
+template<size_t byte_size>
+struct Atomic::PlatformAdd {
+  template<typename D, typename I>
+  inline D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const {
+    D old_value = *dest;
+    while (true) {
+      D new_value = old_value + add_value;
+      D result = cmpxchg(dest, old_value, new_value);
+      if (result == old_value) break;
+      old_value = result;
+    }
+    return old_value + add_value;
+  }
+
+  template<typename D, typename I>
+  inline D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {
+    return add_and_fetch(dest, add_value, order) - add_value;
+  }
+};
+
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,
+                                             T exchange_value,
+                                             atomic_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  __asm__ volatile (  "swap [%2],%0"
+                    : "=r" (exchange_value)
+                    : "0" (exchange_value), "r" (dest)
+                    : "memory");
+  return exchange_value;
+}
+
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,
+                                             T exchange_value,
+                                             atomic_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  T old_value = *dest;
+  while (true) {
+    T result = cmpxchg(dest, old_value, exchange_value);
+    if (result == old_value) break;
+    old_value = result;
+  }
+  return old_value;
+}
+
+// No direct support for cmpxchg of bytes; emulate using int.
+template<>
+struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,
+                                                T compare_value,
+                                                T exchange_value,
+                                                atomic_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  T rv;
+  __asm__ volatile(
+    " cas    [%2], %3, %0"
+    : "=r" (rv)
+    : "0" (exchange_value), "r" (dest), "r" (compare_value)
+    : "memory");
+  return rv;
+}
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,
+                                                T compare_value,
+                                                T exchange_value,
+                                                atomic_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  T rv;
+  __asm__ volatile(
+    " casx   [%2], %3, %0"
+    : "=r" (rv)
+    : "0" (exchange_value), "r" (dest), "r" (compare_value)
+    : "memory");
+  return rv;
+}
+
+#endif // OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp	2023-04-16 11:42:17.119483995 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
+
+#include "utilities/globalDefinitions.hpp"
+
+inline unsigned count_trailing_zeros(uintx x) {
+  assert(x != 0, "precondition");
+  // Reduce to mask with ones in all positions below the least
+  // significant set bit of x, and zeros otherwise.
+  uintx rx = (x - 1) & ~x;      // sub x, 1, rx; andn rx, x, rx;
+  // Then count the set bits in the reduction.
+  uintx result;
+  __asm__(" popc %1, %0\n\t" : "=r" (result) : "r" (rx));
+  return result;
+}
+
+#endif // OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp	2023-04-16 11:42:17.119590998 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
+
+// Sets the default values for platform dependent flags used by the runtime system.
+// (see globals.hpp)
+
+define_pd_global(size_t, JVMInvokeMethodSlack,   12288);
+
+// Used on 64 bit platforms for UseCompressedOops base address
+// use 6G as default base address because by default the OS maps the application
+// to 4G on Solaris-Sparc. This leaves at least 2G for the native heap.
+define_pd_global(size_t, HeapBaseMinAddress,     CONST64(6)*G);
+
+#endif // OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp	2023-04-16 12:14:52.818840181 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
+
+// Included in orderAccess.hpp header file.
+
+// Compiler version last used for testing: solaris studio 12u3
+// Please update this information when this file changes
+
+// Implementation of class OrderAccess.
+
+// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions
+static inline void compiler_barrier() {
+  __asm__ volatile ("" : : : "memory");
+}
+
+inline void OrderAccess::loadload()   { compiler_barrier(); }
+inline void OrderAccess::storestore() { compiler_barrier(); }
+inline void OrderAccess::loadstore()  { compiler_barrier(); }
+inline void OrderAccess::storeload()  { fence();            }
+
+inline void OrderAccess::acquire()    { compiler_barrier(); }
+inline void OrderAccess::release()    { compiler_barrier(); }
+
+inline void OrderAccess::fence() {
+  __asm__ volatile ("membar  #StoreLoad" : : : "memory");
+}
+
+inline void OrderAccess::cross_modify_fence_impl() { }
+
+#endif // OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp
--- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp	2023-04-16 12:14:52.819146703 +0000
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. 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.
+ *
+ */
+
+// no precompiled headers
+#include "jvm.h"
+#include "asm/macroAssembler.hpp"
+#include "macroAssembler_sparc.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/allocation.inline.hpp"
+#include "nativeInst_sparc.hpp"
+#include "os_share_solaris.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm_misc.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/java.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/safepointMechanism.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/timer.hpp"
+#include "signals_posix.hpp"
+#include "utilities/events.hpp"
+#include "utilities/vmError.hpp"
+
+# include <signal.h>        // needed first to avoid name collision for "std" with SC 5.0
+
+// put OS-includes here
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <pthread.h>
+# include <errno.h>
+# include <dlfcn.h>
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/resource.h>
+# include <thread.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/filio.h>
+# include <sys/utsname.h>
+# include <sys/systeminfo.h>
+# include <sys/socket.h>
+# include <sys/lwp.h>
+# include <poll.h>
+# include <sys/lwp.h>
+
+# define _STRUCTURED_PROC 1  //  this gets us the new structured proc interfaces of 5.6 & later
+# include <sys/procfs.h>     //  see comment in <sys/procfs.h>
+
+
+#define MAX_PATH (2 * K)
+
+// Minimum usable stack sizes required to get to user code. Space for
+// HotSpot guard pages is added later.
+size_t os::Posix::_compiler_thread_min_stack_allowed = 104 * K;
+size_t os::Posix::_java_thread_min_stack_allowed = 86 * K;
+size_t os::Posix::_vm_internal_thread_min_stack_allowed = 128 * K;
+
+static void handle_unflushed_register_windows(gwindows_t *win) {
+  int restore_count = win->wbcnt;
+  int i;
+
+  for(i=0; i<restore_count; i++) {
+    address sp = ((address)win->spbuf[i]) + STACK_BIAS;
+    address reg_win = (address)&win->wbuf[i];
+    memcpy(sp,reg_win,sizeof(struct rwindow));
+  }
+}
+
+char* os::non_memory_address_word() {
+  // Must never look like an address returned by reserve_memory,
+  // even in its subfields (as defined by the CPU immediate fields,
+  // if the CPU splits constants across multiple instructions).
+  // On SPARC, 0 != %hi(any real address), because there is no
+  // allocation in the first 1Kb of the virtual address space.
+  return (char*) 0;
+}
+
+//
+// Validate a ucontext retrieved from walking a uc_link of a ucontext.
+// There are issues with libthread giving out uc_links for different threads
+// on the same uc_link chain and bad or circular links.
+//
+bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) {
+  if (valid >= suspect ||
+      valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags ||
+      valid->uc_stack.ss_sp    != suspect->uc_stack.ss_sp    ||
+      valid->uc_stack.ss_size  != suspect->uc_stack.ss_size) {
+    DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");)
+    return false;
+  }
+
+  if (thread->is_Java_thread()) {
+    if (!thread->is_in_full_stack_checked((address)suspect)) {
+      DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");)
+      return false;
+    }
+    address _sp   = (address)((intptr_t)suspect->uc_mcontext.gregs[REG_SP] + STACK_BIAS);
+    if (!thread->is_in_full_stack_checked(_sp) ||
+        !frame::is_valid_stack_pointer(((JavaThread*)thread)->base_of_stack_pointer(), (intptr_t*)_sp)) {
+      DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");)
+      return false;
+    }
+  }
+  return true;
+}
+
+// We will only follow one level of uc_link since there are libthread
+// issues with ucontext linking and it is better to be safe and just
+// let caller retry later.
+const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
+  const ucontext_t *uc) {
+
+  const ucontext_t *retuc = NULL;
+
+  // Sometimes the topmost register windows are not properly flushed.
+  // i.e., if the kernel would have needed to take a page fault
+  if (uc != NULL && uc->uc_mcontext.gwins != NULL) {
+    ::handle_unflushed_register_windows(uc->uc_mcontext.gwins);
+  }
+
+  if (uc != NULL) {
+    if (uc->uc_link == NULL) {
+      // cannot validate without uc_link so accept current ucontext
+      retuc = uc;
+    } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) {
+      // first ucontext is valid so try the next one
+      uc = uc->uc_link;
+      if (uc->uc_link == NULL) {
+        // cannot validate without uc_link so accept current ucontext
+        retuc = uc;
+      } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) {
+        // the ucontext one level down is also valid so return it
+        retuc = uc;
+      }
+    }
+  }
+  return retuc;
+}
+
+void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) {
+  uc->uc_mcontext.gregs [REG_PC]  = (greg_t) pc;
+  uc->uc_mcontext.gregs [REG_nPC] = (greg_t) (pc + 4);
+}
+
+// Assumes ucontext is valid
+intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) {
+  return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS);
+}
+
+// Solaris X86 only
+intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) {
+  ShouldNotReachHere();
+  return NULL;
+}
+
+address os::Posix::ucontext_get_pc(const ucontext_t *uc) {
+  return (address) uc->uc_mcontext.gregs[REG_PC];
+}
+
+
+// ret_fp parameter is only used by Solaris X86.
+address os::fetch_frame_from_context(const void* ucVoid,
+                    intptr_t** ret_sp, intptr_t** ret_fp) {
+
+  address  epc;
+  const ucontext_t *uc = (const ucontext_t*)ucVoid;
+
+  if (uc != NULL) {
+    epc = os::Posix::ucontext_get_pc(uc);
+    if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc);
+  } else {
+    epc = NULL;
+    if (ret_sp) *ret_sp = (intptr_t *)NULL;
+  }
+
+  return epc;
+}
+
+frame os::fetch_frame_from_context(const void* ucVoid) {
+  intptr_t* sp;
+  intptr_t* fp;
+  address epc = fetch_frame_from_context(ucVoid, &sp, &fp);
+  return frame(sp, frame::unpatchable, epc);
+}
+
+frame os::fetch_compiled_frame_from_context(const void* ucVoid) {
+  const ucontext_t* uc = (const ucontext_t*)ucVoid;
+  frame fr = os::fetch_frame_from_context(uc);
+  // in compiled code, the stack banging is performed just after the return pc
+  // has been pushed on the stack
+  // Returned frame will be the caller of the method that faults on the stack bang.
+  // Register window not yet rotated (happens at SAVE after stack bang), so there is no new
+  // frame to go with the faulting PC. Using caller SP that is still in SP, and caller PC
+  // that was written to O7 at call.
+  address pc = (address)uc->uc_mcontext.gregs[REG_O7];
+  return frame(fr.sp(), frame::unpatchable, pc);
+}
+
+frame os::get_sender_for_C_frame(frame* fr) {
+  return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc());
+}
+
+// Returns an estimate of the current stack pointer. Result must be guaranteed to
+// point into the calling threads stack, and be no lower than the current stack
+// pointer.
+address os::current_stack_pointer() {
+  register void *sp __asm__ ("sp");
+  return (address)sp;
+}
+
+frame os::current_frame() {
+  intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()();
+  frame myframe(sp, frame::unpatchable,
+                CAST_FROM_FN_PTR(address, os::current_frame));
+  if (os::is_first_C_frame(&myframe)) {
+    // stack is not walkable
+    return frame(NULL, NULL, false);
+  } else {
+    return os::get_sender_for_C_frame(&myframe);
+  }
+}
+
+bool os::is_allocatable(size_t bytes) {
+  return true;
+}
+
+bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
+                                             ucontext_t* uc, JavaThread* thread) {
+
+  if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
+    // can't decode this kind of signal
+    info = NULL;
+  } else {
+    assert(sig == info->si_signo, "bad siginfo");
+  }
+
+  // decide if this trap can be handled by a stub
+  address stub = NULL;
+
+  address pc          = NULL;
+  address npc         = NULL;
+
+  //%note os_trap_1
+  if (info != NULL && uc != NULL && thread != NULL) {
+    // factor me: getPCfromContext
+    pc = (address) uc->uc_mcontext.gregs[REG_PC];
+    npc = (address) uc->uc_mcontext.gregs[REG_nPC];
+
+    // Handle ALL stack overflow variations here
+    if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) {
+      address addr = (address) info->si_addr;
+      if (thread->is_in_full_stack(addr)) {
+        // stack overflow
+        if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
+          return true; // continue
+        }
+      }
+    }
+
+
+    if (thread->thread_state() == _thread_in_vm ||
+         thread->thread_state() == _thread_in_native) {
+      if (sig == SIGBUS && thread->doing_unsafe_access()) {
+        if (UnsafeCopyMemory::contains_pc(pc)) {
+          npc = UnsafeCopyMemory::page_error_continue_pc(pc);
+        }
+        stub = SharedRuntime::handle_unsafe_access(thread, npc);
+      }
+    }
+
+    else if (thread->thread_state() == _thread_in_Java) {
+      // Java thread running in Java code => find exception handler if any
+      // a fault inside compiled code, the interpreter, or a stub
+
+      // Support Safepoint Polling
+      if ( sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) {
+        stub = SharedRuntime::get_poll_stub(pc);
+      }
+
+      // Not needed on x86 solaris because verify_oops doesn't generate
+      // SEGV/BUS like sparc does.
+      if ( (sig == SIGSEGV || sig == SIGBUS)
+           && pc >= MacroAssembler::_verify_oop_implicit_branch[0]
+           && pc <  MacroAssembler::_verify_oop_implicit_branch[1] ) {
+        stub     =  MacroAssembler::_verify_oop_implicit_branch[2];
+        warning("fixed up memory fault in +VerifyOops at address " INTPTR_FORMAT, info->si_addr);
+      }
+
+      // This is not factored because on x86 solaris the patching for
+      // zombies does not generate a SEGV.
+      else if (sig == SIGSEGV && nativeInstruction_at(pc)->is_zombie()) {
+        // zombie method (ld [%g0],%o7 instruction)
+        stub = SharedRuntime::get_handle_wrong_method_stub();
+
+        // At the stub it needs to look like a call from the caller of this
+        // method (not a call from the segv site).
+        pc = (address)uc->uc_mcontext.gregs[REG_O7];
+      }
+      else if (sig == SIGBUS && info->si_code == BUS_OBJERR) {
+        // BugId 4454115: A read from a MappedByteBuffer can fault
+        // here if the underlying file has been truncated.
+        // Do not crash the VM in such a case.
+        CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
+        CompiledMethod* nm = cb->as_compiled_method_or_null();
+        bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc));
+        if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
+          if (is_unsafe_arraycopy) {
+            npc = UnsafeCopyMemory::page_error_continue_pc(pc);
+          }
+          stub = SharedRuntime::handle_unsafe_access(thread, npc);
+        }
+      }
+      else
+      if (sig == SIGFPE && info->si_code == FPE_INTDIV) {
+        // integer divide by zero
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
+      }
+      else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) {
+        // floating-point divide by zero
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
+      }
+#ifdef COMPILER2
+      else if (sig == SIGILL && nativeInstruction_at(pc)->is_ic_miss_trap()) {
+#ifdef ASSERT
+  #if COMPILER1_AND_COMPILER2
+        CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
+        assert(cb->is_compiled_by_c2(), "Wrong compiler");
+  #endif // COMPILER1_AND_COMPILER2
+#endif // ASSERT
+        // Inline cache missed and user trap "Tne G0+ST_RESERVED_FOR_USER_0+2" taken.
+        stub = SharedRuntime::get_ic_miss_stub();
+        // At the stub it needs to look like a call from the caller of this
+        // method (not a call from the segv site).
+        pc = (address)uc->uc_mcontext.gregs[REG_O7];
+      }
+#endif  // COMPILER2
+
+      else if (sig == SIGSEGV && info->si_code > 0 && MacroAssembler::uses_implicit_null_check(info->si_addr)) {
+        // Determination of interpreter/vtable stub/compiled code null exception
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+      }
+    }
+
+    // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
+    // and the heap gets shrunk before the field access.
+    if ((sig == SIGSEGV) || (sig == SIGBUS)) {
+      address addr = JNI_FastGetField::find_slowcase_pc(pc);
+      if (addr != (address)-1) {
+        stub = addr;
+      }
+    }
+  }
+
+  if (stub != NULL) {
+    // save all thread context in case we need to restore it
+
+    thread->set_saved_exception_pc(pc);
+    thread->set_saved_exception_npc(npc);
+
+    // simulate a branch to the stub (a "call" in the safepoint stub case)
+    // factor me: setPC
+    os::Posix::ucontext_set_pc(uc, stub);
+    return true;
+  }
+
+  return false;
+}
+
+void os::print_context(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+  st->print_cr("Registers:");
+
+  st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
+               " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT,
+            uc->uc_mcontext.gregs[REG_G1],
+            uc->uc_mcontext.gregs[REG_G2],
+            uc->uc_mcontext.gregs[REG_G3],
+            uc->uc_mcontext.gregs[REG_G4]);
+  st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT
+               " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT,
+            uc->uc_mcontext.gregs[REG_G5],
+            uc->uc_mcontext.gregs[REG_G6],
+            uc->uc_mcontext.gregs[REG_G7],
+            uc->uc_mcontext.gregs[REG_Y]);
+  st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT
+               " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
+                 uc->uc_mcontext.gregs[REG_O0],
+                 uc->uc_mcontext.gregs[REG_O1],
+                 uc->uc_mcontext.gregs[REG_O2],
+                 uc->uc_mcontext.gregs[REG_O3]);
+  st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT
+               " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT,
+            uc->uc_mcontext.gregs[REG_O4],
+            uc->uc_mcontext.gregs[REG_O5],
+            uc->uc_mcontext.gregs[REG_O6],
+            uc->uc_mcontext.gregs[REG_O7]);
+
+
+  intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
+  st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
+               " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
+               sp[L0->sp_offset_in_saved_window()],
+               sp[L1->sp_offset_in_saved_window()],
+               sp[L2->sp_offset_in_saved_window()],
+               sp[L3->sp_offset_in_saved_window()]);
+  st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
+               " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
+               sp[L4->sp_offset_in_saved_window()],
+               sp[L5->sp_offset_in_saved_window()],
+               sp[L6->sp_offset_in_saved_window()],
+               sp[L7->sp_offset_in_saved_window()]);
+  st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT
+               " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT,
+               sp[I0->sp_offset_in_saved_window()],
+               sp[I1->sp_offset_in_saved_window()],
+               sp[I2->sp_offset_in_saved_window()],
+               sp[I3->sp_offset_in_saved_window()]);
+  st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT
+               " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT,
+               sp[I4->sp_offset_in_saved_window()],
+               sp[I5->sp_offset_in_saved_window()],
+               sp[I6->sp_offset_in_saved_window()],
+               sp[I7->sp_offset_in_saved_window()]);
+
+  st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT,
+            uc->uc_mcontext.gregs[REG_PC],
+            uc->uc_mcontext.gregs[REG_nPC]);
+  st->cr();
+  st->cr();
+}
+
+void os::print_tos_pc(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t* uc = (const ucontext_t*)context;
+
+  address sp = (address)os::Solaris::ucontext_get_sp(uc);
+  print_tos(st, sp);
+  st->cr();
+
+  // Note: it may be unsafe to inspect memory near pc. For example, pc may
+  // point to garbage if entry point in an nmethod is corrupted. Leave
+  // this at the end, and hope for the best.
+  address pc = os::Posix::ucontext_get_pc(uc);
+  print_instructions(st, pc, sizeof(char));
+  st->cr();
+}
+
+void os::print_register_info(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+  intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
+
+  st->print_cr("Register to memory mapping:");
+  st->cr();
+
+  // this is only for the "general purpose" registers
+  st->print("G1="); print_location(st, uc->uc_mcontext.gregs[REG_G1]);
+  st->print("G2="); print_location(st, uc->uc_mcontext.gregs[REG_G2]);
+  st->print("G3="); print_location(st, uc->uc_mcontext.gregs[REG_G3]);
+  st->print("G4="); print_location(st, uc->uc_mcontext.gregs[REG_G4]);
+  st->print("G5="); print_location(st, uc->uc_mcontext.gregs[REG_G5]);
+  st->print("G6="); print_location(st, uc->uc_mcontext.gregs[REG_G6]);
+  st->print("G7="); print_location(st, uc->uc_mcontext.gregs[REG_G7]);
+  st->cr();
+
+  st->print("O0="); print_location(st, uc->uc_mcontext.gregs[REG_O0]);
+  st->print("O1="); print_location(st, uc->uc_mcontext.gregs[REG_O1]);
+  st->print("O2="); print_location(st, uc->uc_mcontext.gregs[REG_O2]);
+  st->print("O3="); print_location(st, uc->uc_mcontext.gregs[REG_O3]);
+  st->print("O4="); print_location(st, uc->uc_mcontext.gregs[REG_O4]);
+  st->print("O5="); print_location(st, uc->uc_mcontext.gregs[REG_O5]);
+  st->print("O6="); print_location(st, uc->uc_mcontext.gregs[REG_O6]);
+  st->print("O7="); print_location(st, uc->uc_mcontext.gregs[REG_O7]);
+  st->cr();
+
+  st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]);
+  st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]);
+  st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]);
+  st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]);
+  st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]);
+  st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]);
+  st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]);
+  st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]);
+  st->cr();
+
+  st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]);
+  st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]);
+  st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]);
+  st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]);
+  st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]);
+  st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]);
+  st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]);
+  st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]);
+  st->cr();
+}
+
+void os::Solaris::init_thread_fpu_state(void) {
+    // Nothing needed on Sparc.
+}
+
+#ifndef PRODUCT
+void os::verify_stack_alignment() {
+}
+#endif
+
+int os::extra_bang_size_in_bytes() {
+  // SPARC does not require an additional stack bang.
+  return 0;
+}
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp	2023-04-16 11:42:17.120175611 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP
+
+  //
+  // NOTE: we are back in class os here, not Solaris
+  //
+  static void setup_fpu() {}
+  static int32_t  (*atomic_xchg_func)        (int32_t,  volatile int32_t*);
+  static int32_t  (*atomic_cmpxchg_func)     (int32_t,  volatile int32_t*, int32_t);
+  static int64_t  (*atomic_cmpxchg_long_func)(int64_t,  volatile int64_t*, int64_t);
+  static int32_t  (*atomic_add_func)         (int32_t,  volatile int32_t*);
+
+  static int32_t  atomic_xchg_bootstrap        (int32_t,  volatile int32_t*);
+  static int32_t  atomic_cmpxchg_bootstrap     (int32_t,  volatile int32_t*, int32_t);
+  static int64_t  atomic_cmpxchg_long_bootstrap(int64_t,  volatile int64_t*, int64_t);
+  static int32_t  atomic_add_bootstrap         (int32_t,  volatile int32_t*);
+
+  static bool is_allocatable(size_t bytes);
+
+  // Used to register dynamic code cache area with the OS
+  // Note: Currently only used in 64 bit Windows implementations
+  static bool register_code_area(char *low, char *high) { return true; }
+
+#endif // OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp b/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp	2023-04-16 12:14:52.819320391 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP
+#define OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP
+
+#include "runtime/prefetch.hpp"
+
+inline void Prefetch::read(void *loc, intx interval) {
+  __asm__ volatile("prefetch [%0+%1], 0" : : "r" (loc), "r" (interval) : "memory" );
+}
+
+inline void Prefetch::write(void *loc, intx interval) {
+  __asm__ volatile("prefetch [%0+%1], 2" : : "r" (loc), "r" (interval) : "memory" );
+}
+
+#endif // OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il
--- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il	2023-04-16 11:42:17.120394568 +0000
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2002, 2017, Oracle and/or its affiliates. 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.
+//
+//
+
+  // Get the raw thread ID from %g7
+
+       .inline  _raw_thread_id, 0
+       .register %g7,#scratch
+       .volatile
+       mov     %g7, %o0
+       .nonvolatile
+       .end
+
+
+  // Support for jlong Atomic::load and Atomic::store on v9.
+  //
+  // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst)
+  //
+  // Arguments:
+  //      src:  O0
+  //      dest: O1
+  //
+  // Overwrites O2
+
+        .inline _Atomic_move_long_v9,2
+        .volatile
+        ldx     [%o0], %o2
+        stx     %o2, [%o1]
+        .nonvolatile
+        .end
+
+  // Support for void Copy::conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count)
+  //
+  // 32-bit
+  //
+  // Arguments:
+  //      from:  O0
+  //      to:    O1
+  //      count: O2 treated as signed
+  //
+  // Clobbers:
+  //      long_value: O2, O3
+  //      count:      O4
+  //
+  // if (from > to) {
+  //   while (--count >= 0) {
+  //     *to++ = *from++;
+  //   }
+  // } else {
+  //   while (--count >= 0) {
+  //     to[count] = from[count];
+  //   }
+  // }
+        .inline _Copy_conjoint_jlongs_atomic, 3
+        .volatile
+        cmp     %o0, %o1
+        bleu    4f
+        sll     %o2, 3, %o4
+        ba      2f
+    1:
+        subcc   %o4, 8, %o4
+        std     %o2, [%o1]
+        add     %o0, 8, %o0
+        add     %o1, 8, %o1
+    2:
+        bge,a   1b
+        ldd     [%o0], %o2
+        ba      5f
+        nop
+    3:
+        std     %o2, [%o1+%o4]
+    4:
+        subcc   %o4, 8, %o4
+        bge,a   3b
+        ldd     [%o0+%o4], %o2
+    5:
+        .nonvolatile
+        .end
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.S b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.S
--- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.S	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.S	2023-04-16 11:42:17.120498439 +0000
@@ -0,0 +1,82 @@
+!!
+!! Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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.
+!!
+
+    !! Possibilities:
+    !! -- membar
+    !! -- CAS (SP + BIAS, G0, G0)
+    !! -- wr %g0, %asi
+
+    .global SpinPause
+    .align  32
+SpinPause:
+    retl
+    mov %g0, %o0
+
+
+ 
+    .globl _Copy_conjoint_jlongs_atomic
+    .align 32
+    .global   _Copy_conjoint_jlongs_atomic
+ _Copy_conjoint_jlongs_atomic:
+         cmp     %o0, %o1
+         bleu    4f
+         sll     %o2, 3, %o4
+         ba      2f
+    1:
+         subcc   %o4, 8, %o4
+         std     %o2, [%o1]
+         add     %o0, 8, %o0
+         add     %o1, 8, %o1
+    2:
+         bge,a   1b
+         ldd     [%o0], %o2
+         ba      5f
+         nop
+    3:
+         std     %o2, [%o1+%o4]
+    4:
+         subcc   %o4, 8, %o4
+         bge,a   3b
+         ldd     [%o0+%o4], %o2
+    5:      
+         retl
+         nop
+ 
+ 
+  
+    .globl _raw_thread_id
+    .align 32
+ _raw_thread_id:
+    .register %g7, #scratch
+        retl
+        mov     %g7, %o0
+ 
+
+    .globl _flush_reg_windows
+    .align 32
+ _flush_reg_windows:
+        ta 0x03
+        retl
+        mov     %fp, %o0
+ 
+ 
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp
--- a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp	2023-04-16 11:42:17.120632724 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. 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 "precompiled.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+frame JavaThread::pd_last_frame() {
+  assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
+  assert(_anchor.walkable(), "thread has not dumped its register windows yet");
+
+  assert(_anchor.last_Java_pc() != NULL, "Ack no pc!");
+  return frame(last_Java_sp(), frame::unpatchable, _anchor.last_Java_pc());
+}
+
+// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
+// currently interrupted by SIGPROF
+//
+// NOTE: On Solaris, register windows are flushed in the signal handler
+// except for possibly the top frame.
+//
+bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
+  void* ucontext, bool isInJava) {
+  assert(Thread::current() == this, "caller must be current thread");
+  return pd_get_top_frame(fr_addr, ucontext, isInJava, true);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+  // get ucontext somehow
+  return pd_get_top_frame(fr_addr, ucontext, isInJava, false);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr,
+  void* ucontext, bool isInJava, bool makeWalkable) {
+  assert(this->is_Java_thread(), "must be JavaThread");
+  JavaThread* jt = (JavaThread *)this;
+
+  if (!isInJava && makeWalkable) {
+    // make_walkable flushes register windows and grabs last_Java_pc
+    // which can not be done if the ucontext sp matches last_Java_sp
+    // stack walking utilities assume last_Java_pc set if marked flushed
+    jt->frame_anchor()->make_walkable(jt);
+  }
+
+  // If we have a walkable last_Java_frame, then we should use it
+  // even if isInJava == true. It should be more reliable than
+  // ucontext info.
+  if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
+    *fr_addr = jt->pd_last_frame();
+    return true;
+  }
+
+  ucontext_t* uc = (ucontext_t*) ucontext;
+
+  // At this point, we don't have a walkable last_Java_frame, so
+  // we try to glean some information out of the ucontext.
+  intptr_t* ret_sp;
+  address addr = os::fetch_frame_from_context(uc,
+    &ret_sp, NULL /* ret_fp only used on Solaris X86 */);
+  if (addr == NULL || ret_sp == NULL) {
+    // ucontext wasn't useful
+    return false;
+  }
+
+  frame ret_frame(ret_sp, frame::unpatchable, addr);
+
+  // we were running Java code when SIGPROF came in
+  if (isInJava) {
+
+
+    // If the frame we got is safe then it is most certainly valid
+    if (ret_frame.safe_for_sender(jt)) {
+      *fr_addr = ret_frame;
+      return true;
+    }
+
+    // If it isn't safe then we can try several things to try and get
+    // a good starting point.
+    //
+    // On sparc the frames are almost certainly walkable in the sense
+    // of sp/fp linkages. However because of recycling of windows if
+    // a piece of code does multiple save's where the initial save creates
+    // a real frame with a return pc and the succeeding save's are used to
+    // simply get free registers and have no real pc then the pc linkage on these
+    // "inner" temporary frames will be bogus.
+    // Since there is in general only a nesting level like
+    // this one deep in general we'll try and unwind such an "inner" frame
+    // here ourselves and see if it makes sense
+
+    frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr);
+
+    if (unwind_frame.safe_for_sender(jt)) {
+      *fr_addr = unwind_frame;
+      return true;
+    }
+
+    // Well that didn't work. Most likely we're toast on this tick
+    // The previous code would try this. I think it is dubious in light
+    // of changes to safe_for_sender and the unwind trick above but
+    // if it gets us a safe frame who wants to argue.
+
+    // If we have a last_Java_sp, then the SIGPROF signal caught us
+    // right when we were transitioning from _thread_in_Java to a new
+    // JavaThreadState. We use last_Java_sp instead of the sp from
+    // the ucontext since it should be more reliable.
+
+    if (jt->has_last_Java_frame()) {
+      ret_sp = jt->last_Java_sp();
+      frame ret_frame2(ret_sp, frame::unpatchable, addr);
+      if (ret_frame2.safe_for_sender(jt)) {
+        *fr_addr = ret_frame2;
+        return true;
+      }
+    }
+
+    // This is the best we can do. We will only be able to decode the top frame
+
+    *fr_addr = ret_frame;
+    return true;
+  }
+
+  // At this point, we know we weren't running Java code. We might
+  // have a last_Java_sp, but we don't have a walkable frame.
+  // However, we might still be able to construct something useful
+  // if the thread was running native code.
+  if (jt->has_last_Java_frame()) {
+    assert(!jt->frame_anchor()->walkable(), "case covered above");
+
+    frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr);
+    *fr_addr = ret_frame;
+    return true;
+  }
+
+  // nothing else to try but what we found initially
+
+  *fr_addr = ret_frame;
+  return true;
+
+}
+
+void JavaThread::cache_global_variables() { }
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp	2023-04-16 11:42:17.120749608 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP
+
+private:
+  void pd_initialize() {
+    _anchor.clear();
+    _base_of_stack_pointer        = NULL;
+  }
+
+  frame pd_last_frame();
+
+  // Sometimes the trap handler needs to record both PC and NPC.
+  // This is a SPARC-specific companion to Thread::set_saved_exception_pc.
+  address _saved_exception_npc;
+
+  // In polling_page_safepoint_handler_blob(s) we have to tail call other
+  // blobs without blowing any registers.  A tail call requires some
+  // register to jump with and we can't blow any registers, so it must
+  // be restored in the delay slot.  'restore' cannot be used as it
+  // will chop the heads off of 64-bit %o registers in the 32-bit
+  // build.  Instead we reload the registers using G2_thread and this
+  // location.  Must be 64bits in the 32-bit LION build.
+  jdouble _o_reg_temps[6];
+
+  // a stack pointer older than any java frame stack pointer.  It is
+  // used to validate stack pointers in frame::next_younger_sp (it
+  // provides the upper bound in the range check).  This is necessary
+  // on Solaris/SPARC since the ucontext passed to a signal handler is
+  // sometimes corrupt and we need a way to check the extracted sp.
+  intptr_t* _base_of_stack_pointer;
+
+public:
+
+  static int o_reg_temps_offset_in_bytes() { return offset_of(JavaThread, _o_reg_temps); }
+
+  static ByteSize saved_exception_npc_offset() { return byte_offset_of(JavaThread,_saved_exception_npc); }
+
+  address  saved_exception_npc()             { return _saved_exception_npc; }
+  void set_saved_exception_npc(address a)    { _saved_exception_npc = a; }
+
+
+public:
+
+  intptr_t* base_of_stack_pointer() { return _base_of_stack_pointer; }
+
+  void set_base_of_stack_pointer(intptr_t* base_sp) {
+    _base_of_stack_pointer = base_sp;
+  }
+
+  bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
+    bool isInJava);
+  bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
+    bool isInJava);
+private:
+  bool pd_get_top_frame(frame* fr_addr, void* ucontext,
+    bool isInJava, bool makeWalkable);
+
+#endif // OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp	2023-04-16 11:42:17.120853319 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP
+#define OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP
+
+// These are the OS and CPU-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+  nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*)
+
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
+  declare_constant(JavaFrameAnchor::flushed)
+
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#endif // OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP
diff -ur --new-file a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp
--- a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp	1970-01-01 01:00:00.000000000 +0000
+++ b/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp	2023-04-16 12:14:42.529363587 +0000
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. 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 "precompiled.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/vm_version.hpp"
+
+#include <sys/auxv.h>
+#include <sys/systeminfo.h>
+#include <picl.h>
+#include <dlfcn.h>
+#include <link.h>
+
+extern "C" int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result);
+
+// Functions from the library we need (signatures should match those in picl.h)
+extern "C" {
+  typedef int (*picl_initialize_func_t)(void);
+  typedef int (*picl_shutdown_func_t)(void);
+  typedef int (*picl_get_root_func_t)(picl_nodehdl_t *nodehandle);
+  typedef int (*picl_walk_tree_by_class_func_t)(picl_nodehdl_t rooth,
+      const char *classname, void *c_args,
+      int (*callback_fn)(picl_nodehdl_t hdl, void *args));
+  typedef int (*picl_get_prop_by_name_func_t)(picl_nodehdl_t nodeh, const char *nm,
+      picl_prophdl_t *ph);
+  typedef int (*picl_get_propval_func_t)(picl_prophdl_t proph, void *valbuf, size_t sz);
+  typedef int (*picl_get_propinfo_func_t)(picl_prophdl_t proph, picl_propinfo_t *pi);
+}
+
+class PICL {
+  // Pointers to functions in the library
+  picl_initialize_func_t _picl_initialize;
+  picl_shutdown_func_t _picl_shutdown;
+  picl_get_root_func_t _picl_get_root;
+  picl_walk_tree_by_class_func_t _picl_walk_tree_by_class;
+  picl_get_prop_by_name_func_t _picl_get_prop_by_name;
+  picl_get_propval_func_t _picl_get_propval;
+  picl_get_propinfo_func_t _picl_get_propinfo;
+  // Handle to the library that is returned by dlopen
+  void *_dl_handle;
+
+  bool open_library();
+  void close_library();
+
+  template<typename FuncType> bool bind(FuncType& func, const char* name);
+  bool bind_library_functions();
+
+  // Get a value of the integer property. The value in the tree can be either 32 or 64 bit
+  // depending on the platform. The result is converted to int.
+  int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
+    picl_propinfo_t pinfo;
+    picl_prophdl_t proph;
+    if (_picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
+        _picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
+      return PICL_FAILURE;
+    }
+
+    if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
+      assert(false, "Invalid property type");
+      return PICL_FAILURE;
+    }
+    if (pinfo.size == sizeof(int64_t)) {
+      int64_t val;
+      if (_picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
+        return PICL_FAILURE;
+      }
+      *result = static_cast<int>(val);
+    } else if (pinfo.size == sizeof(int32_t)) {
+      int32_t val;
+      if (_picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
+        return PICL_FAILURE;
+      }
+      *result = static_cast<int>(val);
+    } else {
+      assert(false, "Unexpected integer property size");
+      return PICL_FAILURE;
+    }
+    return PICL_SUCCESS;
+  }
+
+  // Visitor and a state machine that visits integer properties and verifies that the
+  // values are the same. Stores the unique value observed.
+  class UniqueValueVisitor {
+    PICL *_picl;
+    enum {
+      INITIAL,        // Start state, no assignments happened
+      ASSIGNED,       // Assigned a value
+      INCONSISTENT    // Inconsistent value seen
+    } _state;
+    int _value;
+  public:
+    UniqueValueVisitor(PICL* picl) : _picl(picl), _state(INITIAL) { }
+    int value() {
+      assert(_state == ASSIGNED, "Precondition");
+      return _value;
+    }
+    void set_value(int value) {
+      assert(_state == INITIAL, "Precondition");
+      _value = value;
+      _state = ASSIGNED;
+    }
+    bool is_initial()       { return _state == INITIAL;      }
+    bool is_assigned()      { return _state == ASSIGNED;     }
+    bool is_inconsistent()  { return _state == INCONSISTENT; }
+    void set_inconsistent() { _state = INCONSISTENT;         }
+
+    bool visit(picl_nodehdl_t nodeh, const char* name) {
+      assert(!is_inconsistent(), "Precondition");
+      int curr;
+      if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
+        if (!is_assigned()) { // first iteration
+          set_value(curr);
+        } else if (curr != value()) { // following iterations
+          set_inconsistent();
+        }
+        return true;
+      }
+      return false;
+    }
+  };
+
+  class CPUVisitor {
+    UniqueValueVisitor _l1_visitor;
+    UniqueValueVisitor _l2_visitor;
+    int _limit; // number of times visit() can be run
+  public:
+    CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {}
+    static int visit(picl_nodehdl_t nodeh, void *arg) {
+      CPUVisitor *cpu_visitor = static_cast<CPUVisitor*>(arg);
+      UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor();
+      UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor();
+      if (!l1_visitor->is_inconsistent()) {
+        l1_visitor->visit(nodeh, "l1-dcache-line-size");
+      }
+      static const char* l2_data_cache_line_property_name = NULL;
+      // On the first visit determine the name of the l2 cache line size property and memoize it.
+      if (l2_data_cache_line_property_name == NULL) {
+        assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent");
+        l2_data_cache_line_property_name = "l2-cache-line-size";
+        if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) {
+          l2_data_cache_line_property_name = "l2-dcache-line-size";
+          l2_visitor->visit(nodeh, l2_data_cache_line_property_name);
+        }
+      } else {
+        if (!l2_visitor->is_inconsistent()) {
+          l2_visitor->visit(nodeh, l2_data_cache_line_property_name);
+        }
+      }
+
+      if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) {
+        return PICL_WALK_TERMINATE;
+      }
+      cpu_visitor->_limit--;
+      if (cpu_visitor->_limit <= 0) {
+        return PICL_WALK_TERMINATE;
+      }
+      return PICL_WALK_CONTINUE;
+    }
+    UniqueValueVisitor* l1_visitor() { return &_l1_visitor; }
+    UniqueValueVisitor* l2_visitor() { return &_l2_visitor; }
+  };
+  int _L1_data_cache_line_size;
+  int _L2_data_cache_line_size;
+public:
+  static int visit_cpu(picl_nodehdl_t nodeh, void *state) {
+    return CPUVisitor::visit(nodeh, state);
+  }
+
+  PICL(bool is_fujitsu, bool is_sun4v) : _dl_handle(NULL), _L1_data_cache_line_size(0), _L2_data_cache_line_size(0) {
+    if (!open_library()) {
+      return;
+    }
+    if (_picl_initialize() == PICL_SUCCESS) {
+      picl_nodehdl_t rooth;
+      if (_picl_get_root(&rooth) == PICL_SUCCESS) {
+        const char* cpu_class = "cpu";
+        // If it's a Fujitsu machine, it's a "core"
+        if (is_fujitsu) {
+          cpu_class = "core";
+        }
+        CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count());
+        _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper);
+        if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value?
+          _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value();
+        }
+        if (cpu_visitor.l2_visitor()->is_assigned()) {
+          _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value();
+        }
+      }
+      _picl_shutdown();
+    }
+    close_library();
+  }
+
+  unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
+  unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; }
+};
+
+
+extern "C" int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) {
+  return PICL::visit_cpu(nodeh, result);
+}
+
+template<typename FuncType>
+bool PICL::bind(FuncType& func, const char* name) {
+  func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name));
+  return func != NULL;
+}
+
+bool PICL::bind_library_functions() {
+  assert(_dl_handle != NULL, "library should be open");
+  return bind(_picl_initialize,         "picl_initialize"        ) &&
+         bind(_picl_shutdown,           "picl_shutdown"          ) &&
+         bind(_picl_get_root,           "picl_get_root"          ) &&
+         bind(_picl_walk_tree_by_class, "picl_walk_tree_by_class") &&
+         bind(_picl_get_prop_by_name,   "picl_get_prop_by_name"  ) &&
+         bind(_picl_get_propval,        "picl_get_propval"       ) &&
+         bind(_picl_get_propinfo,       "picl_get_propinfo"      );
+}
+
+bool PICL::open_library() {
+  _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY);
+  if (_dl_handle == NULL) {
+    return false;
+  }
+  if (!bind_library_functions()) {
+    assert(false, "unexpected PICL API change");
+    close_library();
+    return false;
+  }
+  return true;
+}
+
+void PICL::close_library() {
+  assert(_dl_handle != NULL, "library should be open");
+  dlclose(_dl_handle);
+  _dl_handle = NULL;
+}
+
+class Sysinfo {
+  char* _string;
+public:
+  Sysinfo(int si) : _string(NULL) {
+    char   tmp;
+    size_t bufsize = sysinfo(si, &tmp, 1);
+
+    if (bufsize != -1) {
+      char* buf = (char*) os::malloc(bufsize, mtInternal);
+      if (buf != NULL) {
+        if (sysinfo(si, buf, bufsize) == bufsize) {
+          _string = buf;
+        } else {
+          os::free(buf);
+        }
+      }
+    }
+  }
+
+  ~Sysinfo() {
+    if (_string != NULL) {
+      os::free(_string);
+    }
+  }
+
+  const char* value() const {
+    return _string;
+  }
+
+  bool valid() const {
+    return _string != NULL;
+  }
+
+  bool match(const char* s) const {
+    return valid() ? strcmp(_string, s) == 0 : false;
+  }
+
+  bool match_substring(const char* s) const {
+    return valid() ? strstr(_string, s) != NULL : false;
+  }
+};
+
+class Sysconf {
+  int _value;
+public:
+  Sysconf(int sc) : _value(-1) {
+    _value = sysconf(sc);
+  }
+  bool valid() const {
+    return _value != -1;
+  }
+  int value() const {
+    return _value;
+  }
+};
+
+
+#ifndef _SC_DCACHE_LINESZ
+#define _SC_DCACHE_LINESZ       508     /* Data cache line size */
+#endif
+
+#ifndef _SC_L2CACHE_LINESZ
+#define _SC_L2CACHE_LINESZ      527     /* Size of L2 cache line */
+#endif
+
+#ifndef AV_HW1_IDX
+#define AV_HW1_IDX 0
+#endif
+
+#ifndef AV_HW2_IDX
+#define AV_HW2_IDX 1
+#endif
+
+void VM_Version::platform_features() {
+  uint64_t features = ISA_v9_msk;   // Basic SPARC-V9 required (V8 not supported).
+
+  assert(Sysinfo(SI_ARCHITECTURE_64).match("sparcv9"), "must be");
+
+  // Extract valid instruction set extensions.
+  uint32_t avs[AV_HW2_IDX + 1];
+  uint_t avn = getisax(avs, AV_HW2_IDX + 1);
+  assert(avn <= 2, "should return two or less av's");
+
+  log_info(os, cpu)("getisax(2) returned %d words:", avn);
+  for (int i = 0; i < avn; i++) {
+    log_info(os, cpu)("    word %d: " PTR32_FORMAT, i, avs[i]);
+  }
+
+  uint32_t av = avs[AV_HW1_IDX];
+
+  // Obsolete and 32b legacy mode capabilities NOT probed here, despite being
+  // set by Solaris 11.4 (onward) also on V9; AV_SPARC_MUL32, AV_SPARC_DIV32
+  // and AV_SPARC_FSMULD (and AV_SPARC_V8PLUS).
+
+  if (av & AV_SPARC_POPC) features |= ISA_popc_msk;
+  if (av & AV_SPARC_VIS)  features |= ISA_vis1_msk;
+  if (av & AV_SPARC_VIS2) features |= ISA_vis2_msk;
+
+  // Hardware capability defines introduced after Solaris 11.1:
+
+#ifndef AV_SPARC_FMAF
+#define AV_SPARC_FMAF         0x00000100 // Fused Multiply-Add
+#endif
+
+  if (av & AV_SPARC_ASI_BLK_INIT) features |= ISA_blk_init_msk;
+  if (av & AV_SPARC_FMAF)         features |= ISA_fmaf_msk;
+  if (av & AV_SPARC_VIS3)         features |= ISA_vis3_msk;
+  if (av & AV_SPARC_HPC)          features |= ISA_hpc_msk;
+  if (av & AV_SPARC_IMA)          features |= ISA_ima_msk;
+  if (av & AV_SPARC_AES)          features |= ISA_aes_msk;
+  if (av & AV_SPARC_DES)          features |= ISA_des_msk;
+  if (av & AV_SPARC_KASUMI)       features |= ISA_kasumi_msk;
+  if (av & AV_SPARC_CAMELLIA)     features |= ISA_camellia_msk;
+  if (av & AV_SPARC_MD5)          features |= ISA_md5_msk;
+  if (av & AV_SPARC_SHA1)         features |= ISA_sha1_msk;
+  if (av & AV_SPARC_SHA256)       features |= ISA_sha256_msk;
+  if (av & AV_SPARC_SHA512)       features |= ISA_sha512_msk;
+  if (av & AV_SPARC_MPMUL)        features |= ISA_mpmul_msk;
+  if (av & AV_SPARC_MONT)         features |= ISA_mont_msk;
+  if (av & AV_SPARC_PAUSE)        features |= ISA_pause_msk;
+  if (av & AV_SPARC_CBCOND)       features |= ISA_cbcond_msk;
+  if (av & AV_SPARC_CRC32C)       features |= ISA_crc32c_msk;
+
+#ifndef AV2_SPARC_FJATHPLUS
+#define AV2_SPARC_FJATHPLUS  0x00000001 // Fujitsu Athena+ insns
+#endif
+#ifndef AV2_SPARC_VIS3B
+#define AV2_SPARC_VIS3B      0x00000002 // VIS3 present on multiple chips
+#endif
+#ifndef AV2_SPARC_ADI
+#define AV2_SPARC_ADI        0x00000004 // Application Data Integrity
+#endif
+#ifndef AV2_SPARC_SPARC5
+#define AV2_SPARC_SPARC5     0x00000008 // The 29 new fp and sub instructions
+#endif
+#ifndef AV2_SPARC_MWAIT
+#define AV2_SPARC_MWAIT      0x00000010 // mwait instruction and load/monitor ASIs
+#endif
+#ifndef AV2_SPARC_XMPMUL
+#define AV2_SPARC_XMPMUL     0x00000020 // XOR multiple precision multiply
+#endif
+#ifndef AV2_SPARC_XMONT
+#define AV2_SPARC_XMONT      0x00000040 // XOR Montgomery mult/sqr instructions
+#endif
+#ifndef AV2_SPARC_PAUSE_NSEC
+#define AV2_SPARC_PAUSE_NSEC 0x00000080 // pause instruction with support for nsec timings
+#endif
+#ifndef AV2_SPARC_VAMASK
+#define AV2_SPARC_VAMASK     0x00000100 // Virtual Address masking
+#endif
+
+#ifndef AV2_SPARC_SPARC6
+#define AV2_SPARC_SPARC6     0x00000200 // REVB*, FPSLL*, RDENTROPY, LDM* and STM*
+#endif
+#ifndef AV2_SPARC_DICTUNP
+#define AV2_SPARC_DICTUNP    0x00002000 // Dictionary unpack instruction
+#endif
+#ifndef AV2_SPARC_FPCMPSHL
+#define AV2_SPARC_FPCMPSHL   0x00004000 // Partition compare with shifted result
+#endif
+#ifndef AV2_SPARC_RLE
+#define AV2_SPARC_RLE        0x00008000 // Run-length encoded burst and length
+#endif
+#ifndef AV2_SPARC_SHA3
+#define AV2_SPARC_SHA3       0x00010000 // SHA3 instructions
+#endif
+#ifndef AV2_SPARC_FJATHPLUS2
+#define AV2_SPARC_FJATHPLUS2 0x00020000 // Fujitsu Athena++ insns
+#endif
+#ifndef AV2_SPARC_VIS3C
+#define AV2_SPARC_VIS3C      0x00040000 // Subset of VIS3 insns provided by Athena++
+#endif
+#ifndef AV2_SPARC_SPARC5B
+#define AV2_SPARC_SPARC5B    0x00080000 // subset of SPARC5 insns (fpadd8, fpsub8)
+#endif
+#ifndef AV2_SPARC_MME
+#define AV2_SPARC_MME        0x00100000 // Misaligned Mitigation Enable
+#endif
+
+  if (avn > 1) {
+    uint32_t av2 = avs[AV_HW2_IDX];
+
+    if (av2 & AV2_SPARC_FJATHPLUS)  features |= ISA_fjathplus_msk;
+    if (av2 & AV2_SPARC_VIS3B)      features |= ISA_vis3b_msk;
+    if (av2 & AV2_SPARC_ADI)        features |= ISA_adi_msk;
+    if (av2 & AV2_SPARC_SPARC5)     features |= ISA_sparc5_msk;
+    if (av2 & AV2_SPARC_MWAIT)      features |= ISA_mwait_msk;
+    if (av2 & AV2_SPARC_XMPMUL)     features |= ISA_xmpmul_msk;
+    if (av2 & AV2_SPARC_XMONT)      features |= ISA_xmont_msk;
+    if (av2 & AV2_SPARC_PAUSE_NSEC) features |= ISA_pause_nsec_msk;
+    if (av2 & AV2_SPARC_VAMASK)     features |= ISA_vamask_msk;
+
+    if (av2 & AV2_SPARC_SPARC6)     features |= ISA_sparc6_msk;
+    if (av2 & AV2_SPARC_DICTUNP)    features |= ISA_dictunp_msk;
+    if (av2 & AV2_SPARC_FPCMPSHL)   features |= ISA_fpcmpshl_msk;
+    if (av2 & AV2_SPARC_RLE)        features |= ISA_rle_msk;
+    if (av2 & AV2_SPARC_SHA3)       features |= ISA_sha3_msk;
+    if (av2 & AV2_SPARC_FJATHPLUS2) features |= ISA_fjathplus2_msk;
+    if (av2 & AV2_SPARC_VIS3C)      features |= ISA_vis3c_msk;
+    if (av2 & AV2_SPARC_SPARC5B)    features |= ISA_sparc5b_msk;
+    if (av2 & AV2_SPARC_MME)        features |= ISA_mme_msk;
+  }
+
+  _features = features;     // ISA feature set completed, update state.
+
+  Sysinfo machine(SI_MACHINE);
+
+  bool is_sun4v = machine.match("sun4v");   // All Oracle SPARC + Fujitsu Athena+/++
+  bool is_sun4u = machine.match("sun4u");   // All other Fujitsu
+
+  // Handle Athena+/++ conservatively (simply because we are lacking info.).
+
+  bool an_athena = has_athena_plus() || has_athena_plus2();
+  bool do_sun4v  = is_sun4v && !an_athena;
+  bool do_sun4u  = is_sun4u ||  an_athena;
+
+  uint64_t synthetic = 0;
+
+  if (do_sun4v) {
+    // Indirect and direct branches are equally fast.
+    synthetic = CPU_fast_ind_br_msk;
+    // Fast IDIV, BIS and LD available on Niagara Plus.
+    if (has_vis2()) {
+      synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk);
+      // ...on Core C4 however, we prefer not to use BIS.
+      if (!has_sparc5()) {
+        synthetic |= CPU_fast_bis_msk;
+      }
+    }
+    // SPARC Core C3 supports fast RDPC and block zeroing.
+    if (has_ima()) {
+      synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk);
+    }
+    // SPARC Core C3 and C4 have slow CMOVE.
+    if (!has_ima()) {
+      synthetic |= CPU_fast_cmove_msk;
+    }
+  } else if (do_sun4u) {
+    // SPARC64 only have fast IDIV and RDPC.
+    synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk);
+  } else {
+    log_info(os, cpu)("Unable to derive CPU features: %s", machine.value());
+  }
+
+  _features += synthetic;   // Including CPU derived/synthetic features.
+
+  Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ);
+  Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ);
+
+  // Require both Sysconf requests to be valid or use fall-back.
+
+  if (l1_dcache_line_size.valid() &&
+      l2_dcache_line_size.valid()) {
+    _L1_data_cache_line_size = l1_dcache_line_size.value();
+    _L2_data_cache_line_size = l2_dcache_line_size.value();
+  } else {
+    // Otherwise figure out the cache line sizes using PICL.
+    PICL picl(is_sun4u, is_sun4v);
+    _L1_data_cache_line_size = picl.L1_data_cache_line_size();
+    _L2_data_cache_line_size = picl.L2_data_cache_line_size();
+  }
+}
