mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-09 07:35:49 +00:00
Merge branch 'master' into cas-alloc-1
This commit is contained in:
commit
30931d5aaa
@ -1385,10 +1385,9 @@ dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb .</code></pre></li>
|
||||
can specify it by <code>--with-alsa</code>.</p></li>
|
||||
</ul>
|
||||
<h4 id="x11-1">X11</h4>
|
||||
<p>You will need X11 libraries suitable for your <em>target</em> system.
|
||||
In most cases, using Debian's pre-built libraries work fine.</p>
|
||||
<p>Note that X11 is needed even if you only want to build a headless
|
||||
JDK.</p>
|
||||
<p>When not building a headless JDK, you will need X11 libraries
|
||||
suitable for your <em>target</em> system. In most cases, using Debian's
|
||||
pre-built libraries work fine.</p>
|
||||
<ul>
|
||||
<li><p>Go to <a href="https://www.debian.org/distrib/packages">Debian
|
||||
Package Search</a>, search for the following packages for your
|
||||
|
||||
@ -1178,10 +1178,8 @@ Note that alsa is needed even if you only want to build a headless JDK.
|
||||
|
||||
#### X11
|
||||
|
||||
You will need X11 libraries suitable for your *target* system. In most cases,
|
||||
using Debian's pre-built libraries work fine.
|
||||
|
||||
Note that X11 is needed even if you only want to build a headless JDK.
|
||||
When not building a headless JDK, you will need X11 libraries suitable for your
|
||||
*target* system. In most cases, using Debian's pre-built libraries work fine.
|
||||
|
||||
* Go to [Debian Package Search](https://www.debian.org/distrib/packages),
|
||||
search for the following packages for your *target* system, and download them
|
||||
|
||||
@ -965,9 +965,8 @@ rather than <code>NULL</code>. See the paper for reasons to avoid
|
||||
<code>NULL</code>.</p>
|
||||
<p>Don't use (constant expression or literal) 0 for pointers. Note that
|
||||
C++14 removed non-literal 0 constants from <em>null pointer
|
||||
constants</em>, though some compilers continue to treat them as such.
|
||||
For historical reasons there may be lingering uses of 0 as a
|
||||
pointer.</p>
|
||||
constants</em>, though some compilers continue to treat them as
|
||||
such.</p>
|
||||
<h3 id="atomic"><atomic></h3>
|
||||
<p>Do not use facilities provided by the <code><atomic></code>
|
||||
header (<a
|
||||
|
||||
@ -884,8 +884,7 @@ rather than `NULL`. See the paper for reasons to avoid `NULL`.
|
||||
|
||||
Don't use (constant expression or literal) 0 for pointers. Note that C++14
|
||||
removed non-literal 0 constants from _null pointer constants_, though some
|
||||
compilers continue to treat them as such. For historical reasons there may be
|
||||
lingering uses of 0 as a pointer.
|
||||
compilers continue to treat them as such.
|
||||
|
||||
### <atomic>
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2026, 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
|
||||
@ -209,7 +209,10 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
|
||||
BUILD_CC_DISABLE_WARNING_PREFIX="-wd"
|
||||
CFLAGS_WARNINGS_ARE_ERRORS="-WX"
|
||||
|
||||
WARNINGS_ENABLE_ALL="-W3"
|
||||
WARNINGS_ENABLE_ALL_NORMAL="-W3"
|
||||
WARNINGS_ENABLE_ADDITIONAL=""
|
||||
WARNINGS_ENABLE_ADDITIONAL_CXX=""
|
||||
WARNINGS_ENABLE_ADDITIONAL_JVM=""
|
||||
DISABLED_WARNINGS="4800 5105"
|
||||
;;
|
||||
|
||||
@ -218,14 +221,16 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
|
||||
BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-"
|
||||
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
|
||||
|
||||
WARNINGS_ENABLE_ALL_NORMAL="-Wall -Wextra"
|
||||
|
||||
# Additional warnings that are not activated by -Wall and -Wextra
|
||||
WARNINGS_ENABLE_ADDITIONAL="-Winvalid-pch -Wpointer-arith -Wreturn-type \
|
||||
WARNINGS_ENABLE_ADDITIONAL="-Wformat=2 \
|
||||
-Winvalid-pch -Wpointer-arith -Wreturn-type \
|
||||
-Wsign-compare -Wtrampolines -Wtype-limits -Wundef -Wuninitialized \
|
||||
-Wunused-const-variable=1 -Wunused-function -Wunused-result \
|
||||
-Wunused-value"
|
||||
WARNINGS_ENABLE_ADDITIONAL_CXX="-Woverloaded-virtual -Wreorder"
|
||||
WARNINGS_ENABLE_ALL_CFLAGS="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
|
||||
WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX"
|
||||
WARNINGS_ENABLE_ADDITIONAL_JVM="-Wzero-as-null-pointer-constant"
|
||||
|
||||
# These warnings will never be turned on, since they generate too many
|
||||
# false positives.
|
||||
@ -241,16 +246,24 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
|
||||
BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-"
|
||||
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
|
||||
|
||||
WARNINGS_ENABLE_ALL_NORMAL="-Wall -Wextra"
|
||||
|
||||
# Additional warnings that are not activated by -Wall and -Wextra
|
||||
WARNINGS_ENABLE_ADDITIONAL="-Wpointer-arith -Wsign-compare -Wreorder \
|
||||
WARNINGS_ENABLE_ADDITIONAL="-Wformat=2 \
|
||||
-Wpointer-arith -Wsign-compare -Wreorder \
|
||||
-Wunused-function -Wundef -Wunused-value -Woverloaded-virtual"
|
||||
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
|
||||
WARNINGS_ENABLE_ADDITIONAL_CXX=""
|
||||
WARNINGS_ENABLE_ADDITIONAL_JVM="-Wzero-as-null-pointer-constant"
|
||||
|
||||
# These warnings will never be turned on, since they generate too many
|
||||
# false positives.
|
||||
DISABLED_WARNINGS="unknown-warning-option unused-parameter"
|
||||
;;
|
||||
esac
|
||||
WARNINGS_ENABLE_ALL="$WARNINGS_ENABLE_ALL_NORMAL $WARNINGS_ENABLE_ADDITIONAL"
|
||||
WARNINGS_ENABLE_ALL_CXX="$WARNINGS_ENABLE_ALL $WARNINGS_ENABLE_ADDITIONAL_CXX"
|
||||
WARNINGS_ENABLE_ALL_JVM="$WARNINGS_ENABLE_ALL_CXX $WARNINGS_ENABLE_ADDITIONAL_JVM"
|
||||
|
||||
AC_SUBST(DISABLE_WARNING_PREFIX)
|
||||
AC_SUBST(BUILD_CC_DISABLE_WARNING_PREFIX)
|
||||
AC_SUBST(CFLAGS_WARNINGS_ARE_ERRORS)
|
||||
@ -604,19 +617,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
|
||||
ADLC_LANGSTD_CXXFLAGS="$LANGSTD_CXXFLAGS"
|
||||
|
||||
# CFLAGS WARNINGS STUFF
|
||||
# Set JVM_CFLAGS warning handling
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc; then
|
||||
WARNING_CFLAGS_JDK_CONLY="$WARNINGS_ENABLE_ALL_CFLAGS"
|
||||
WARNING_CFLAGS_JDK_CXXONLY="$WARNINGS_ENABLE_ALL_CXXFLAGS"
|
||||
WARNING_CFLAGS_JVM="$WARNINGS_ENABLE_ALL_CXXFLAGS"
|
||||
|
||||
elif test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
WARNING_CFLAGS="$WARNINGS_ENABLE_ALL"
|
||||
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
WARNING_CFLAGS="$WARNINGS_ENABLE_ALL"
|
||||
|
||||
fi
|
||||
WARNING_CFLAGS_JDK_CONLY="$WARNINGS_ENABLE_ALL"
|
||||
WARNING_CFLAGS_JDK_CXXONLY="$WARNINGS_ENABLE_ALL_CXX"
|
||||
WARNING_CFLAGS_JVM="$WARNINGS_ENABLE_ALL_JVM"
|
||||
|
||||
# Set some additional per-OS defines.
|
||||
|
||||
@ -878,12 +881,12 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
|
||||
CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \
|
||||
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
|
||||
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
|
||||
$WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
|
||||
$REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
|
||||
|
||||
CFLAGS_JDK_COMMON="$ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
|
||||
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
|
||||
$DEBUG_SYMBOLS_CFLAGS_JDK \
|
||||
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
|
||||
|
||||
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2018, 2026, 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
|
||||
@ -28,7 +28,7 @@
|
||||
################################################################################
|
||||
|
||||
# Minimum supported versions
|
||||
JTREG_MINIMUM_VERSION=8.1
|
||||
JTREG_MINIMUM_VERSION=8.2.1
|
||||
GTEST_MINIMUM_VERSION=1.14.0
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -42,12 +42,12 @@ m4_include([lib-tests.m4])
|
||||
AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
|
||||
[
|
||||
# Check if X11 is needed
|
||||
if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then
|
||||
# No X11 support on windows or macosx
|
||||
if test "x$OPENJDK_TARGET_OS" = xwindows ||
|
||||
test "x$OPENJDK_TARGET_OS" = xmacosx ||
|
||||
test "x$ENABLE_HEADLESS_ONLY" = xtrue; then
|
||||
NEEDS_LIB_X11=false
|
||||
else
|
||||
# All other instances need X11, even if building headless only, libawt still
|
||||
# needs X11 headers.
|
||||
# All other instances need X11 for libawt.
|
||||
NEEDS_LIB_X11=true
|
||||
fi
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2020, 2026, 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
|
||||
@ -26,7 +26,7 @@
|
||||
# Versions and download locations for dependencies used by GitHub Actions (GHA)
|
||||
|
||||
GTEST_VERSION=1.14.0
|
||||
JTREG_VERSION=8.1+1
|
||||
JTREG_VERSION=8.2.1+1
|
||||
|
||||
LINUX_X64_BOOT_JDK_EXT=tar.gz
|
||||
LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_linux-x64_bin.tar.gz
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2026, 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
|
||||
@ -1174,9 +1174,9 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
jtreg: {
|
||||
server: "jpg",
|
||||
product: "jtreg",
|
||||
version: "8.1",
|
||||
version: "8.2.1",
|
||||
build_number: "1",
|
||||
file: "bundles/jtreg-8.1+1.zip",
|
||||
file: "bundles/jtreg-8.2.1+1.zip",
|
||||
environment_name: "JT_HOME",
|
||||
environment_path: input.get("jtreg", "home_path") + "/bin",
|
||||
configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"),
|
||||
|
||||
@ -78,7 +78,7 @@ else ifeq ($(BASE_OS), Fedora)
|
||||
endif
|
||||
BASE_URL := http://fedora.riscv.rocks/repos-dist/f$(BASE_OS_VERSION)/latest/$(ARCH)/Packages/
|
||||
else
|
||||
LATEST_ARCHIVED_OS_VERSION := 36
|
||||
LATEST_ARCHIVED_OS_VERSION := 41
|
||||
ifeq ($(filter aarch64 armhfp x86_64, $(ARCH)), )
|
||||
FEDORA_TYPE := fedora-secondary
|
||||
else
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026, 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
|
||||
@ -293,8 +293,10 @@ public class CLDRConverter {
|
||||
bundleGenerator = new ResourceBundleGenerator();
|
||||
|
||||
// Parse data independent of locales
|
||||
parseSupplemental();
|
||||
// parseBCP47() must precede parseSupplemental(). The latter depends
|
||||
// on IANA alias map, which is produced by the former.
|
||||
parseBCP47();
|
||||
parseSupplemental();
|
||||
|
||||
// rules maps
|
||||
pluralRules = generateRules(handlerPlurals);
|
||||
@ -536,6 +538,12 @@ public class CLDRConverter {
|
||||
|
||||
// canonical tz name map
|
||||
// alias -> primary
|
||||
//
|
||||
// Note that CLDR meta zones do not necessarily align with IANA's
|
||||
// current time zone identifiers. For example, the CLDR "India"
|
||||
// meta zone maps to "Asia/Calcutta", whereas IANA now uses
|
||||
// "Asia/Kolkata" for the zone. Accordingly, "canonical" here is
|
||||
// defined in terms of CLDR's zone mappings.
|
||||
handlerTimeZone.getData().forEach((k, v) -> {
|
||||
String[] ids = ((String)v).split("\\s");
|
||||
for (int i = 1; i < ids.length; i++) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2026, 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
|
||||
@ -27,6 +27,9 @@ package build.tools.cldrconverter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
@ -40,6 +43,10 @@ import org.xml.sax.SAXException;
|
||||
class TimeZoneParseHandler extends AbstractLDMLHandler<Object> {
|
||||
private static final String PREF_PREFIX = "preferred:";
|
||||
|
||||
// CLDR aliases to IANA ids map. The initial capacity is estimated
|
||||
// from the number of aliases in timezone.xml as of CLDR v48
|
||||
private final Map<String, String> ianaAliasMap = HashMap.newHashMap(32);
|
||||
|
||||
@Override
|
||||
public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException {
|
||||
// avoid HTTP traffic to unicode.org
|
||||
@ -61,7 +68,16 @@ class TimeZoneParseHandler extends AbstractLDMLHandler<Object> {
|
||||
put(attributes.getValue("name"), PREF_PREFIX + preferred);
|
||||
}
|
||||
} else {
|
||||
put(attributes.getValue("name"), attributes.getValue("alias"));
|
||||
var alias = attributes.getValue("alias");
|
||||
var iana = attributes.getValue("iana");
|
||||
if (iana != null) {
|
||||
for (var a : alias.split("\\s+")) {
|
||||
if (!a.equals(iana)) {
|
||||
ianaAliasMap.put(a, iana);
|
||||
}
|
||||
}
|
||||
}
|
||||
put(attributes.getValue("name"), alias);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -80,4 +96,8 @@ class TimeZoneParseHandler extends AbstractLDMLHandler<Object> {
|
||||
.forEach(e -> map.put(e.getKey(),
|
||||
map.get(e.getValue().toString().substring(PREF_PREFIX.length()))));
|
||||
}
|
||||
|
||||
Map<String, String> getIanaAliasMap() {
|
||||
return ianaAliasMap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, 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
|
||||
@ -56,6 +56,7 @@ class WinZonesParseHandler extends AbstractLDMLHandler<Object> {
|
||||
String zoneName = attributes.getValue("other");
|
||||
String territory = attributes.getValue("territory");
|
||||
String javatz = attributes.getValue("type").replaceFirst("\\s.*", "");
|
||||
javatz = CLDRConverter.handlerTimeZone.getIanaAliasMap().getOrDefault(javatz, javatz);
|
||||
put(zoneName + ":" + territory, javatz);
|
||||
pushIgnoredContainer(qName);
|
||||
break;
|
||||
|
||||
@ -88,6 +88,10 @@ LIBAWT_EXTRA_HEADER_DIRS := \
|
||||
|
||||
LIBAWT_CFLAGS := -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES -DMLIB_NO_LIBSUNMATH
|
||||
|
||||
ifeq ($(ENABLE_HEADLESS_ONLY), true)
|
||||
LIBAWT_CFLAGS += -DHEADLESS
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, windows), true)
|
||||
LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE -DMLIB_OS64BIT
|
||||
LIBAWT_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons
|
||||
@ -167,11 +171,18 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
$(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
|
||||
#
|
||||
|
||||
LIBAWT_HEADLESS_EXCLUDE_FILES := \
|
||||
GLXGraphicsConfig.c \
|
||||
GLXSurfaceData.c \
|
||||
X11PMBlitLoops.c \
|
||||
X11Renderer.c \
|
||||
X11SurfaceData.c \
|
||||
#
|
||||
|
||||
LIBAWT_HEADLESS_EXTRA_HEADER_DIRS := \
|
||||
$(LIBAWT_DEFAULT_HEADER_DIRS) \
|
||||
common/awt/debug \
|
||||
common/font \
|
||||
common/java2d/opengl \
|
||||
java.base:libjvm \
|
||||
#
|
||||
|
||||
@ -191,7 +202,8 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBAWT_HEADLESS, \
|
||||
NAME := awt_headless, \
|
||||
EXTRA_SRC := $(LIBAWT_HEADLESS_EXTRA_SRC), \
|
||||
EXCLUDES := medialib, \
|
||||
EXCLUDES := medialib opengl, \
|
||||
EXCLUDE_FILES := $(LIBAWT_HEADLESS_EXCLUDE_FILES), \
|
||||
ONLY_EXPORTED := $(LIBAWT_HEADLESS_ONLY_EXPORTED), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := -DHEADLESS=true $(CUPS_CFLAGS) $(FONTCONFIG_CFLAGS) \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2018, 2026, 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
|
||||
@ -54,7 +54,7 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGEAPPLAUNCHER, \
|
||||
SRC := applauncher, \
|
||||
EXTRA_SRC := common, \
|
||||
INCLUDE_FILES := $(JPACKAGEAPPLAUNCHER_INCLUDE_FILES), \
|
||||
OPTIMIZATION := LOW, \
|
||||
OPTIMIZATION := SIZE, \
|
||||
DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \
|
||||
DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \
|
||||
DISABLED_WARNINGS_clang_Log.cpp := unused-const-variable, \
|
||||
@ -91,7 +91,7 @@ ifeq ($(call isTargetOs, linux), true)
|
||||
common, \
|
||||
EXCLUDE_FILES := LinuxLauncher.c LinuxPackage.c, \
|
||||
LINK_TYPE := C++, \
|
||||
OPTIMIZATION := LOW, \
|
||||
OPTIMIZATION := SIZE, \
|
||||
DISABLED_WARNINGS_gcc_Log.cpp := unused-const-variable, \
|
||||
DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \
|
||||
DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2020, 2025, Arm Limited. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -201,6 +201,8 @@ source %{
|
||||
case Op_XorReductionV:
|
||||
case Op_MinReductionV:
|
||||
case Op_MaxReductionV:
|
||||
case Op_UMinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
// Reductions with less than 8 bytes vector length are
|
||||
// not supported.
|
||||
if (length_in_bytes < 8) {
|
||||
@ -383,6 +385,8 @@ source %{
|
||||
return !VM_Version::use_neon_for_vector(length_in_bytes);
|
||||
case Op_MinReductionV:
|
||||
case Op_MaxReductionV:
|
||||
case Op_UMinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
// For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON
|
||||
// instructions rather than SVE predicated instructions for
|
||||
// better performance.
|
||||
@ -4218,6 +4222,224 @@ instruct reduce_minD_masked(vRegD dst, vRegD dsrc, vReg vsrc, pRegGov pg) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// -------------------- Vector reduction unsigned min/max ----------------------
|
||||
|
||||
// reduction uminI
|
||||
|
||||
instruct reduce_uminI_neon(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
|
||||
vReg tmp, rFlagsReg cr) %{
|
||||
predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
|
||||
(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_INT));
|
||||
match(Set dst (UMinReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_uminI_neon $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
__ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
length_in_bytes, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_uminI_sve(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
|
||||
(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_INT));
|
||||
match(Set dst (UMinReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_uminI_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
assert(UseSVE > 0, "must be sve");
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
assert(length_in_bytes == MaxVectorSize, "invalid vector length");
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
ptrue, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// reduction uminL
|
||||
|
||||
instruct reduce_uminL_neon(iRegLNoSp dst, iRegL isrc, vReg vsrc, rFlagsReg cr) %{
|
||||
predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
|
||||
match(Set dst (UMinReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, KILL cr);
|
||||
format %{ "reduce_uminL_neon $dst, $isrc, $vsrc\t# 2L. KILL cr" %}
|
||||
ins_encode %{
|
||||
__ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
/* vector_length_in_bytes */ 16, fnoreg);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_uminL_sve(iRegLNoSp dst, iRegL isrc, vReg vsrc,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
|
||||
match(Set dst (UMinReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_uminL_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
assert(length_in_bytes == MaxVectorSize, "invalid vector length");
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
ptrue, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// reduction umin - predicated
|
||||
|
||||
instruct reduce_uminI_masked(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc, pRegGov pg,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 &&
|
||||
(Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_INT));
|
||||
match(Set dst (UMinReductionV (Binary isrc vsrc) pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_uminI_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
$pg$$PRegister, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_uminL_masked(iRegLNoSp dst, iRegL isrc, vReg vsrc, pRegGov pg,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_LONG);
|
||||
match(Set dst (UMinReductionV (Binary isrc vsrc) pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_uminL_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
$pg$$PRegister, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// reduction umaxI
|
||||
|
||||
instruct reduce_umaxI_neon(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
|
||||
vReg tmp, rFlagsReg cr) %{
|
||||
predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
|
||||
(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_INT));
|
||||
match(Set dst (UMaxReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_umaxI_neon $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
__ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
length_in_bytes, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_umaxI_sve(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) &&
|
||||
(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(2)) == T_INT));
|
||||
match(Set dst (UMaxReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_umaxI_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
assert(UseSVE > 0, "must be sve");
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
assert(length_in_bytes == MaxVectorSize, "invalid vector length");
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
ptrue, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// reduction umaxL
|
||||
|
||||
instruct reduce_umaxL_neon(iRegLNoSp dst, iRegL isrc, vReg vsrc, rFlagsReg cr) %{
|
||||
predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
|
||||
match(Set dst (UMaxReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, KILL cr);
|
||||
format %{ "reduce_umaxL_neon $dst, $isrc, $vsrc\t# 2L. KILL cr" %}
|
||||
ins_encode %{
|
||||
__ neon_reduce_minmax_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
/* vector_length_in_bytes */ 16, fnoreg);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_umaxL_sve(iRegLNoSp dst, iRegL isrc, vReg vsrc,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(2)) == T_LONG);
|
||||
match(Set dst (UMaxReductionV isrc vsrc));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_umaxL_sve $dst, $isrc, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
|
||||
assert(length_in_bytes == MaxVectorSize, "invalid vector length");
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, T_LONG,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
ptrue, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// reduction umax - predicated
|
||||
|
||||
instruct reduce_umaxI_masked(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc, pRegGov pg,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 &&
|
||||
(Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_BYTE ||
|
||||
Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_SHORT ||
|
||||
Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_INT));
|
||||
match(Set dst (UMaxReductionV (Binary isrc vsrc) pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_umaxI_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
$pg$$PRegister, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct reduce_umaxL_masked(iRegLNoSp dst, iRegL isrc, vReg vsrc, pRegGov pg,
|
||||
vRegD tmp, rFlagsReg cr) %{
|
||||
predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n->in(1)->in(2)) == T_LONG);
|
||||
match(Set dst (UMaxReductionV (Binary isrc vsrc) pg));
|
||||
effect(TEMP_DEF dst, TEMP tmp, KILL cr);
|
||||
format %{ "reduce_umaxL_masked $dst, $isrc, $pg, $vsrc\t# KILL $tmp, cr" %}
|
||||
ins_encode %{
|
||||
BasicType bt = Matcher::vector_element_basic_type(this, $vsrc);
|
||||
__ sve_reduce_integral(this->ideal_Opcode(), $dst$$Register, bt,
|
||||
$isrc$$Register, $vsrc$$FloatRegister,
|
||||
$pg$$PRegister, $tmp$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// ------------------------------ Vector reinterpret ---------------------------
|
||||
|
||||
instruct reinterpret_same_size(vReg dst_src) %{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2020, 2025, Arm Limited. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
@ -191,6 +191,8 @@ source %{
|
||||
case Op_XorReductionV:
|
||||
case Op_MinReductionV:
|
||||
case Op_MaxReductionV:
|
||||
case Op_UMinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
// Reductions with less than 8 bytes vector length are
|
||||
// not supported.
|
||||
if (length_in_bytes < 8) {
|
||||
@ -373,6 +375,8 @@ source %{
|
||||
return !VM_Version::use_neon_for_vector(length_in_bytes);
|
||||
case Op_MinReductionV:
|
||||
case Op_MaxReductionV:
|
||||
case Op_UMinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
// For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON
|
||||
// instructions rather than SVE predicated instructions for
|
||||
// better performance.
|
||||
@ -2505,6 +2509,32 @@ REDUCE_MAXMIN_INT_PREDICATE(min, L, iRegL, MinReductionV)
|
||||
REDUCE_MAXMIN_FP_PREDICATE(min, F, fsrc, MinReductionV, sve_fminv, fmins)
|
||||
REDUCE_MAXMIN_FP_PREDICATE(min, D, dsrc, MinReductionV, sve_fminv, fmind)
|
||||
|
||||
// -------------------- Vector reduction unsigned min/max ----------------------
|
||||
|
||||
// reduction uminI
|
||||
REDUCE_MAXMIN_I_NEON(umin, UMinReductionV)
|
||||
REDUCE_MAXMIN_I_SVE(umin, UMinReductionV)
|
||||
|
||||
// reduction uminL
|
||||
REDUCE_MAXMIN_L_NEON(umin, UMinReductionV)
|
||||
REDUCE_MAXMIN_L_SVE(umin, UMinReductionV)
|
||||
|
||||
// reduction umin - predicated
|
||||
REDUCE_MAXMIN_INT_PREDICATE(umin, I, iRegIorL2I, UMinReductionV)
|
||||
REDUCE_MAXMIN_INT_PREDICATE(umin, L, iRegL, UMinReductionV)
|
||||
|
||||
// reduction umaxI
|
||||
REDUCE_MAXMIN_I_NEON(umax, UMaxReductionV)
|
||||
REDUCE_MAXMIN_I_SVE(umax, UMaxReductionV)
|
||||
|
||||
// reduction umaxL
|
||||
REDUCE_MAXMIN_L_NEON(umax, UMaxReductionV)
|
||||
REDUCE_MAXMIN_L_SVE(umax, UMaxReductionV)
|
||||
|
||||
// reduction umax - predicated
|
||||
REDUCE_MAXMIN_INT_PREDICATE(umax, I, iRegIorL2I, UMaxReductionV)
|
||||
REDUCE_MAXMIN_INT_PREDICATE(umax, L, iRegL, UMaxReductionV)
|
||||
|
||||
// ------------------------------ Vector reinterpret ---------------------------
|
||||
|
||||
instruct reinterpret_same_size(vReg dst_src) %{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -2658,6 +2658,8 @@ template<typename R, typename... Rx>
|
||||
INSN(uminv, 1, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(smaxp, 0, 0b101001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(sminp, 0, 0b101011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(umaxp, 1, 0b101001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(uminp, 1, 0b101011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
INSN(sqdmulh,0, 0b101101, false); // accepted arrangements: T4H, T8H, T2S, T4S
|
||||
INSN(shsubv, 0, 0b001001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
|
||||
|
||||
@ -3490,7 +3492,9 @@ public:
|
||||
INSN(sve_sub, 0b00000100, 0b000001000); // vector sub
|
||||
INSN(sve_uaddv, 0b00000100, 0b000001001); // unsigned add reduction to scalar
|
||||
INSN(sve_umax, 0b00000100, 0b001001000); // unsigned maximum vectors
|
||||
INSN(sve_umaxv, 0b00000100, 0b001001001); // unsigned maximum reduction to scalar
|
||||
INSN(sve_umin, 0b00000100, 0b001011000); // unsigned minimum vectors
|
||||
INSN(sve_uminv, 0b00000100, 0b001011001); // unsigned minimum reduction to scalar
|
||||
#undef INSN
|
||||
|
||||
// SVE floating-point arithmetic - predicate
|
||||
@ -4325,6 +4329,7 @@ public:
|
||||
#undef INSN
|
||||
|
||||
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
}
|
||||
|
||||
// Stack overflow checking
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, 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
|
||||
@ -1960,50 +1960,76 @@ void C2_MacroAssembler::neon_reduce_logical(int opc, Register dst, BasicType bt,
|
||||
BLOCK_COMMENT("} neon_reduce_logical");
|
||||
}
|
||||
|
||||
// Vector reduction min/max for integral type with ASIMD instructions.
|
||||
// Helper function to decode min/max reduction operation properties
|
||||
void C2_MacroAssembler::decode_minmax_reduction_opc(int opc, bool* is_min,
|
||||
bool* is_unsigned,
|
||||
Condition* cond) {
|
||||
switch(opc) {
|
||||
case Op_MinReductionV:
|
||||
*is_min = true; *is_unsigned = false; *cond = LT; break;
|
||||
case Op_MaxReductionV:
|
||||
*is_min = false; *is_unsigned = false; *cond = GT; break;
|
||||
case Op_UMinReductionV:
|
||||
*is_min = true; *is_unsigned = true; *cond = LO; break;
|
||||
case Op_UMaxReductionV:
|
||||
*is_min = false; *is_unsigned = true; *cond = HI; break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
// Vector reduction min/max/umin/umax for integral type with ASIMD instructions.
|
||||
// Note: vtmp is not used and expected to be fnoreg for T_LONG case.
|
||||
// Clobbers: rscratch1, rflags
|
||||
void C2_MacroAssembler::neon_reduce_minmax_integral(int opc, Register dst, BasicType bt,
|
||||
Register isrc, FloatRegister vsrc,
|
||||
unsigned vector_length_in_bytes,
|
||||
FloatRegister vtmp) {
|
||||
assert(opc == Op_MinReductionV || opc == Op_MaxReductionV, "unsupported");
|
||||
assert(opc == Op_MinReductionV || opc == Op_MaxReductionV ||
|
||||
opc == Op_UMinReductionV || opc == Op_UMaxReductionV, "unsupported");
|
||||
assert(vector_length_in_bytes == 8 || vector_length_in_bytes == 16, "unsupported");
|
||||
assert(bt == T_BYTE || bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported");
|
||||
assert_different_registers(dst, isrc);
|
||||
bool isQ = vector_length_in_bytes == 16;
|
||||
bool is_min = opc == Op_MinReductionV;
|
||||
|
||||
bool is_min;
|
||||
bool is_unsigned;
|
||||
Condition cond;
|
||||
decode_minmax_reduction_opc(opc, &is_min, &is_unsigned, &cond);
|
||||
BLOCK_COMMENT("neon_reduce_minmax_integral {");
|
||||
if (bt == T_LONG) {
|
||||
assert(vtmp == fnoreg, "should be");
|
||||
assert(isQ, "should be");
|
||||
umov(rscratch1, vsrc, D, 0);
|
||||
cmp(isrc, rscratch1);
|
||||
csel(dst, isrc, rscratch1, is_min ? LT : GT);
|
||||
csel(dst, isrc, rscratch1, cond);
|
||||
umov(rscratch1, vsrc, D, 1);
|
||||
cmp(dst, rscratch1);
|
||||
csel(dst, dst, rscratch1, is_min ? LT : GT);
|
||||
csel(dst, dst, rscratch1, cond);
|
||||
} else {
|
||||
SIMD_Arrangement size = esize2arrangement((unsigned)type2aelembytes(bt), isQ);
|
||||
if (size == T2S) {
|
||||
is_min ? sminp(vtmp, size, vsrc, vsrc) : smaxp(vtmp, size, vsrc, vsrc);
|
||||
// For T2S (2x32-bit elements), use pairwise instructions because
|
||||
// uminv/umaxv/sminv/smaxv don't support arrangement 2S.
|
||||
neon_minmaxp(is_unsigned, is_min, vtmp, size, vsrc, vsrc);
|
||||
} else {
|
||||
is_min ? sminv(vtmp, size, vsrc) : smaxv(vtmp, size, vsrc);
|
||||
// For other sizes, use reduction to scalar instructions.
|
||||
neon_minmaxv(is_unsigned, is_min, vtmp, size, vsrc);
|
||||
}
|
||||
if (bt == T_INT) {
|
||||
umov(dst, vtmp, S, 0);
|
||||
} else if (is_unsigned) {
|
||||
umov(dst, vtmp, elemType_to_regVariant(bt), 0);
|
||||
} else {
|
||||
smov(dst, vtmp, elemType_to_regVariant(bt), 0);
|
||||
}
|
||||
cmpw(dst, isrc);
|
||||
cselw(dst, dst, isrc, is_min ? LT : GT);
|
||||
cselw(dst, dst, isrc, cond);
|
||||
}
|
||||
BLOCK_COMMENT("} neon_reduce_minmax_integral");
|
||||
}
|
||||
|
||||
// Vector reduction for integral type with SVE instruction.
|
||||
// Supported operations are Add, And, Or, Xor, Max, Min.
|
||||
// Supported operations are Add, And, Or, Xor, Max, Min, UMax, UMin.
|
||||
// rflags would be clobbered if opc is Op_MaxReductionV or Op_MinReductionV.
|
||||
void C2_MacroAssembler::sve_reduce_integral(int opc, Register dst, BasicType bt, Register src1,
|
||||
FloatRegister src2, PRegister pg, FloatRegister tmp) {
|
||||
@ -2075,35 +2101,27 @@ void C2_MacroAssembler::sve_reduce_integral(int opc, Register dst, BasicType bt,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op_MaxReductionV: {
|
||||
sve_smaxv(tmp, size, pg, src2);
|
||||
if (bt == T_INT || bt == T_LONG) {
|
||||
case Op_MaxReductionV:
|
||||
case Op_MinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
case Op_UMinReductionV: {
|
||||
bool is_min;
|
||||
bool is_unsigned;
|
||||
Condition cond;
|
||||
decode_minmax_reduction_opc(opc, &is_min, &is_unsigned, &cond);
|
||||
sve_minmaxv(is_unsigned, is_min, tmp, size, pg, src2);
|
||||
// Move result from vector to general register
|
||||
if (is_unsigned || bt == T_INT || bt == T_LONG) {
|
||||
umov(dst, tmp, size, 0);
|
||||
} else {
|
||||
smov(dst, tmp, size, 0);
|
||||
}
|
||||
if (bt == T_LONG) {
|
||||
cmp(dst, src1);
|
||||
csel(dst, dst, src1, Assembler::GT);
|
||||
csel(dst, dst, src1, cond);
|
||||
} else {
|
||||
cmpw(dst, src1);
|
||||
cselw(dst, dst, src1, Assembler::GT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Op_MinReductionV: {
|
||||
sve_sminv(tmp, size, pg, src2);
|
||||
if (bt == T_INT || bt == T_LONG) {
|
||||
umov(dst, tmp, size, 0);
|
||||
} else {
|
||||
smov(dst, tmp, size, 0);
|
||||
}
|
||||
if (bt == T_LONG) {
|
||||
cmp(dst, src1);
|
||||
csel(dst, dst, src1, Assembler::LT);
|
||||
} else {
|
||||
cmpw(dst, src1);
|
||||
cselw(dst, dst, src1, Assembler::LT);
|
||||
cselw(dst, dst, src1, cond);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, 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
|
||||
@ -34,6 +34,37 @@
|
||||
void neon_reduce_logical_helper(int opc, bool sf, Register Rd, Register Rn, Register Rm,
|
||||
enum shift_kind kind = Assembler::LSL, unsigned shift = 0);
|
||||
|
||||
// Helper functions for min/max reduction operations
|
||||
|
||||
void decode_minmax_reduction_opc(int opc, bool* is_min, bool* is_unsigned, Condition* cond);
|
||||
|
||||
void neon_minmaxp(bool is_unsigned, bool is_min, FloatRegister dst,
|
||||
SIMD_Arrangement size, FloatRegister src1, FloatRegister src2) {
|
||||
auto m = is_unsigned ? (is_min ? &Assembler::uminp : &Assembler::umaxp)
|
||||
: (is_min ? &Assembler::sminp : &Assembler::smaxp);
|
||||
(this->*m)(dst, size, src1, src2);
|
||||
}
|
||||
|
||||
// Typedefs used to disambiguate overloaded member functions.
|
||||
typedef void (Assembler::*neon_reduction2)
|
||||
(FloatRegister, SIMD_Arrangement, FloatRegister);
|
||||
|
||||
void neon_minmaxv(bool is_unsigned, bool is_min, FloatRegister dst,
|
||||
SIMD_Arrangement size, FloatRegister src) {
|
||||
auto m = is_unsigned ? (is_min ? (neon_reduction2)&Assembler::uminv
|
||||
: (neon_reduction2)&Assembler::umaxv)
|
||||
: (is_min ? &Assembler::sminv
|
||||
: &Assembler::smaxv);
|
||||
(this->*m)(dst, size, src);
|
||||
}
|
||||
|
||||
void sve_minmaxv(bool is_unsigned, bool is_min, FloatRegister dst,
|
||||
SIMD_RegVariant size, PRegister pg, FloatRegister src) {
|
||||
auto m = is_unsigned ? (is_min ? &Assembler::sve_uminv : &Assembler::sve_umaxv)
|
||||
: (is_min ? &Assembler::sve_sminv : &Assembler::sve_smaxv);
|
||||
(this->*m)(dst, size, pg, src);
|
||||
}
|
||||
|
||||
void select_from_two_vectors_neon(FloatRegister dst, FloatRegister src1,
|
||||
FloatRegister src2, FloatRegister index,
|
||||
FloatRegister tmp, unsigned vector_length_in_bytes);
|
||||
|
||||
@ -209,6 +209,10 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
|
||||
bs_asm->increment_patching_epoch();
|
||||
}
|
||||
|
||||
// Enable WXWrite: the function is called directly from nmethod_entry_barrier
|
||||
// stub.
|
||||
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current()));
|
||||
|
||||
NativeNMethodBarrier barrier(nm);
|
||||
barrier.set_value(value, bit_mask);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap nulls
|
||||
define_pd_global(bool, DelayCompilerStubsGeneration, COMPILER2_OR_JVMCI);
|
||||
|
||||
define_pd_global(size_t, CodeCacheSegmentSize, 64);
|
||||
define_pd_global(intx, CodeEntryAlignment, 64);
|
||||
define_pd_global(uint, CodeEntryAlignment, 64);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -473,6 +473,7 @@ address MacroAssembler::target_addr_for_insn(address insn_addr) {
|
||||
// Patch any kind of instruction; there may be several instructions.
|
||||
// Return the total length (in bytes) of the instructions.
|
||||
int MacroAssembler::pd_patch_instruction_size(address insn_addr, address target) {
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
return RelocActions<Patcher>::run(insn_addr, target);
|
||||
}
|
||||
|
||||
@ -481,6 +482,8 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
|
||||
unsigned insn = *(unsigned*)insn_addr;
|
||||
assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
|
||||
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
|
||||
// OOPs are either narrow (32 bits) or wide (48 bits). We encode
|
||||
// narrow OOPs by setting the upper 16 bits in the first
|
||||
// instruction.
|
||||
@ -510,6 +513,8 @@ int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
|
||||
assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
|
||||
nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
|
||||
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
|
||||
Instruction_aarch64::patch(insn_addr, 20, 5, n >> 16);
|
||||
Instruction_aarch64::patch(insn_addr+4, 20, 5, n & 0xffff);
|
||||
return 2 * NativeInstruction::instruction_size;
|
||||
@ -6419,10 +6424,14 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value)
|
||||
|
||||
// Intrinsic for
|
||||
//
|
||||
// - sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray
|
||||
// return the number of characters copied.
|
||||
// - java/lang/StringUTF16.compress
|
||||
// return index of non-latin1 character if copy fails, otherwise 'len'.
|
||||
// - sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes char[] to byte[] in ISO-8859-1
|
||||
//
|
||||
// - java.lang.StringCoding#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes byte[] (containing UTF-16) to byte[] in ISO-8859-1
|
||||
//
|
||||
// - java.lang.StringCoding#encodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes char[] to byte[] in ASCII
|
||||
//
|
||||
// This version always returns the number of characters copied, and does not
|
||||
// clobber the 'len' register. A successful copy will complete with the post-
|
||||
|
||||
@ -133,7 +133,6 @@ void NativeMovConstReg::verify() {
|
||||
|
||||
|
||||
intptr_t NativeMovConstReg::data() const {
|
||||
// das(uint64_t(instruction_address()),2);
|
||||
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
if (maybe_cpool_ref(instruction_address())) {
|
||||
return *(intptr_t*)addr;
|
||||
@ -144,6 +143,7 @@ intptr_t NativeMovConstReg::data() const {
|
||||
|
||||
void NativeMovConstReg::set_data(intptr_t x) {
|
||||
if (maybe_cpool_ref(instruction_address())) {
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
*(intptr_t*)addr = x;
|
||||
} else {
|
||||
@ -350,8 +350,6 @@ bool NativeInstruction::is_stop() {
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void NativeGeneralJump::verify() { }
|
||||
|
||||
// MT-safe patching of a long jump instruction.
|
||||
void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
|
||||
ShouldNotCallThis();
|
||||
|
||||
@ -90,16 +90,18 @@ protected:
|
||||
|
||||
s_char sbyte_at(int offset) const { return *(s_char*)addr_at(offset); }
|
||||
u_char ubyte_at(int offset) const { return *(u_char*)addr_at(offset); }
|
||||
jint int_at(int offset) const { return *(jint*)addr_at(offset); }
|
||||
juint uint_at(int offset) const { return *(juint*)addr_at(offset); }
|
||||
address ptr_at(int offset) const { return *(address*)addr_at(offset); }
|
||||
oop oop_at(int offset) const { return *(oop*)addr_at(offset); }
|
||||
jint int_at(int offset) const { return *(jint*)addr_at(offset); }
|
||||
juint uint_at(int offset) const { return *(juint*)addr_at(offset); }
|
||||
address ptr_at(int offset) const { return *(address*)addr_at(offset); }
|
||||
oop oop_at(int offset) const { return *(oop*)addr_at(offset); }
|
||||
|
||||
void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; }
|
||||
void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; }
|
||||
void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; }
|
||||
void set_ptr_at(int offset, address ptr) { *(address*)addr_at(offset) = ptr; }
|
||||
void set_oop_at(int offset, oop o) { *(oop*)addr_at(offset) = o; }
|
||||
#define MACOS_WX_WRITE MACOS_AARCH64_ONLY(os::thread_wx_enable_write())
|
||||
void set_char_at(int offset, char c) { MACOS_WX_WRITE; *addr_at(offset) = (u_char)c; }
|
||||
void set_int_at(int offset, jint i) { MACOS_WX_WRITE; *(jint*)addr_at(offset) = i; }
|
||||
void set_uint_at(int offset, jint i) { MACOS_WX_WRITE; *(juint*)addr_at(offset) = i; }
|
||||
void set_ptr_at(int offset, address ptr) { MACOS_WX_WRITE; *(address*)addr_at(offset) = ptr; }
|
||||
void set_oop_at(int offset, oop o) { MACOS_WX_WRITE; *(oop*)addr_at(offset) = o; }
|
||||
#undef MACOS_WX_WRITE
|
||||
|
||||
void wrote(int offset);
|
||||
|
||||
@ -380,7 +382,6 @@ public:
|
||||
void set_jump_destination(address dest);
|
||||
|
||||
static void replace_mt_safe(address instr_addr, address code_buffer);
|
||||
static void verify();
|
||||
};
|
||||
|
||||
inline NativeGeneralJump* nativeGeneralJump_at(address address) {
|
||||
|
||||
@ -11742,7 +11742,9 @@ class StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
#endif
|
||||
|
||||
StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory();
|
||||
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_setMemory)) {
|
||||
StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory();
|
||||
}
|
||||
|
||||
StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated
|
||||
}
|
||||
|
||||
@ -201,16 +201,14 @@ void VM_Version::initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Cortex A53
|
||||
if (_cpu == CPU_ARM && model_is(0xd03)) {
|
||||
if (_cpu == CPU_ARM && model_is(CPU_MODEL_ARM_CORTEX_A53)) {
|
||||
set_feature(CPU_A53MAC);
|
||||
if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) {
|
||||
FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Cortex A73
|
||||
if (_cpu == CPU_ARM && model_is(0xd09)) {
|
||||
if (_cpu == CPU_ARM && model_is(CPU_MODEL_ARM_CORTEX_A73)) {
|
||||
if (FLAG_IS_DEFAULT(SoftwarePrefetchHintDistance)) {
|
||||
FLAG_SET_DEFAULT(SoftwarePrefetchHintDistance, -1);
|
||||
}
|
||||
@ -220,16 +218,11 @@ void VM_Version::initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Neoverse
|
||||
// N1: 0xd0c
|
||||
// N2: 0xd49
|
||||
// N3: 0xd8e
|
||||
// V1: 0xd40
|
||||
// V2: 0xd4f
|
||||
// V3: 0xd84
|
||||
if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) ||
|
||||
model_is(0xd40) || model_is(0xd4f) ||
|
||||
model_is(0xd8e) || model_is(0xd84))) {
|
||||
if (_cpu == CPU_ARM &&
|
||||
model_is_in({ CPU_MODEL_ARM_NEOVERSE_N1, CPU_MODEL_ARM_NEOVERSE_V1,
|
||||
CPU_MODEL_ARM_NEOVERSE_N2, CPU_MODEL_ARM_NEOVERSE_V2,
|
||||
CPU_MODEL_ARM_NEOVERSE_N3, CPU_MODEL_ARM_NEOVERSE_V3,
|
||||
CPU_MODEL_ARM_NEOVERSE_V3AE })) {
|
||||
if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) {
|
||||
FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true);
|
||||
}
|
||||
@ -261,12 +254,9 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseCRC32, false);
|
||||
}
|
||||
|
||||
// Neoverse
|
||||
// V1: 0xd40
|
||||
// V2: 0xd4f
|
||||
// V3: 0xd84
|
||||
if (_cpu == CPU_ARM &&
|
||||
(model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) {
|
||||
model_is_in({ CPU_MODEL_ARM_NEOVERSE_V1, CPU_MODEL_ARM_NEOVERSE_V2,
|
||||
CPU_MODEL_ARM_NEOVERSE_V3, CPU_MODEL_ARM_NEOVERSE_V3AE })) {
|
||||
if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) {
|
||||
FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true);
|
||||
}
|
||||
@ -632,6 +622,22 @@ void VM_Version::initialize() {
|
||||
|
||||
check_virtualizations();
|
||||
|
||||
#ifdef __APPLE__
|
||||
DefaultWXWriteMode = UseOldWX ? WXWrite : WXArmedForWrite;
|
||||
|
||||
if (TraceWXHealing) {
|
||||
if (pthread_jit_write_protect_supported_np()) {
|
||||
tty->print_cr("### TraceWXHealing is in use");
|
||||
if (StressWXHealing) {
|
||||
tty->print_cr("### StressWXHealing is in use");
|
||||
}
|
||||
} else {
|
||||
tty->print_cr("WX Healing is not in use because MAP_JIT write protection "
|
||||
"does not work on this system.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sync SVE related CPU features with flags
|
||||
if (UseSVE < 2) {
|
||||
clear_feature(CPU_SVE2);
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
#include "runtime/abstract_vm_version.hpp"
|
||||
#include "utilities/sizes.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
class stringStream;
|
||||
|
||||
#define BIT_MASK(flag) (1ULL<<(flag))
|
||||
@ -112,14 +114,26 @@ public:
|
||||
CPU_APPLE = 'a',
|
||||
};
|
||||
|
||||
enum Ampere_CPU_Model {
|
||||
enum Ampere_CPU_Model {
|
||||
CPU_MODEL_EMAG = 0x0, /* CPU implementer is CPU_AMCC */
|
||||
CPU_MODEL_ALTRA = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
|
||||
CPU_MODEL_ALTRAMAX = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
|
||||
CPU_MODEL_AMPERE_1 = 0xac3, /* CPU implementer is CPU_AMPERE */
|
||||
CPU_MODEL_AMPERE_1A = 0xac4, /* CPU implementer is CPU_AMPERE */
|
||||
CPU_MODEL_AMPERE_1B = 0xac5 /* AMPERE_1B core Implements ARMv8.7 with CSSC, MTE, SM3/SM4 extensions */
|
||||
};
|
||||
};
|
||||
|
||||
enum ARM_CPU_Model {
|
||||
CPU_MODEL_ARM_CORTEX_A53 = 0xd03,
|
||||
CPU_MODEL_ARM_CORTEX_A73 = 0xd09,
|
||||
CPU_MODEL_ARM_NEOVERSE_N1 = 0xd0c,
|
||||
CPU_MODEL_ARM_NEOVERSE_V1 = 0xd40,
|
||||
CPU_MODEL_ARM_NEOVERSE_N2 = 0xd49,
|
||||
CPU_MODEL_ARM_NEOVERSE_V2 = 0xd4f,
|
||||
CPU_MODEL_ARM_NEOVERSE_V3AE = 0xd83,
|
||||
CPU_MODEL_ARM_NEOVERSE_V3 = 0xd84,
|
||||
CPU_MODEL_ARM_NEOVERSE_N3 = 0xd8e,
|
||||
};
|
||||
|
||||
#define CPU_FEATURE_FLAGS(decl) \
|
||||
decl(FP, fp, 0) \
|
||||
@ -181,6 +195,15 @@ enum Ampere_CPU_Model {
|
||||
return _model == cpu_model || _model2 == cpu_model;
|
||||
}
|
||||
|
||||
static bool model_is_in(std::initializer_list<int> cpu_models) {
|
||||
for (const int& cpu_model : cpu_models) {
|
||||
if (_model == cpu_model || _model2 == cpu_model) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_zva_enabled() { return 0 <= _zva_length; }
|
||||
static int zva_length() {
|
||||
assert(is_zva_enabled(), "ZVA not available");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2026, 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
|
||||
@ -37,7 +37,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); // Not needed
|
||||
define_pd_global(bool, DelayCompilerStubsGeneration, false); // No need - only few compiler's stubs
|
||||
|
||||
define_pd_global(size_t, CodeCacheSegmentSize, 64);
|
||||
define_pd_global(intx, CodeEntryAlignment, 16);
|
||||
define_pd_global(uint, CodeEntryAlignment, 16);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026 SAP SE. 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
|
||||
@ -44,7 +44,7 @@ define_pd_global(intx, CompileThreshold, 10000);
|
||||
|
||||
define_pd_global(intx, OnStackReplacePercentage, 140);
|
||||
define_pd_global(intx, ConditionalMoveLimit, 3);
|
||||
define_pd_global(intx, FreqInlineSize, 175);
|
||||
define_pd_global(intx, FreqInlineSize, 325);
|
||||
define_pd_global(intx, MinJumpTableSize, 10);
|
||||
define_pd_global(intx, InteriorEntryAlignment, 16);
|
||||
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -60,7 +60,7 @@ define_pd_global(bool, VMContinuations, true);
|
||||
|
||||
// Use large code-entry alignment.
|
||||
define_pd_global(size_t, CodeCacheSegmentSize, 128);
|
||||
define_pd_global(intx, CodeEntryAlignment, 64);
|
||||
define_pd_global(uint, CodeEntryAlignment, 64);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, InlineSmallCode, 1500);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2025 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2026 SAP SE. 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
|
||||
@ -775,7 +775,6 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
|
||||
return stk;
|
||||
}
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
// Calling convention for calling C code.
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
VMRegPair *regs,
|
||||
@ -913,7 +912,6 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
return MAX2(arg, 8) * 2 + additional_frame_header_slots;
|
||||
#endif
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
int SharedRuntime::vector_calling_convention(VMRegPair *regs,
|
||||
uint num_bits,
|
||||
@ -2874,7 +2872,6 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
|
||||
Label exec_mode_initialized;
|
||||
int frame_size_in_words;
|
||||
OopMap* map = nullptr;
|
||||
OopMapSet *oop_maps = new OopMapSet();
|
||||
|
||||
@ -2886,6 +2883,9 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
const Register exec_mode_reg = R21_tmp1;
|
||||
|
||||
const address start = __ pc();
|
||||
int exception_offset = 0;
|
||||
int exception_in_tls_offset = 0;
|
||||
int reexecute_offset = 0;
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
// --------------------------------------------------------------------------
|
||||
@ -2925,7 +2925,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// - R3_ARG1: exception oop
|
||||
// - R4_ARG2: exception pc
|
||||
|
||||
int exception_offset = __ pc() - start;
|
||||
exception_offset = __ pc() - start;
|
||||
|
||||
BLOCK_COMMENT("Prolog for exception case");
|
||||
|
||||
@ -2936,7 +2936,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ std(R4_ARG2, _abi0(lr), R1_SP);
|
||||
|
||||
// Vanilla deoptimization with an exception pending in exception_oop.
|
||||
int exception_in_tls_offset = __ pc() - start;
|
||||
exception_in_tls_offset = __ pc() - start;
|
||||
|
||||
// Push the "unpack frame".
|
||||
// Save everything in sight.
|
||||
@ -2949,8 +2949,6 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ li(exec_mode_reg, Deoptimization::Unpack_exception);
|
||||
|
||||
// fall through
|
||||
|
||||
int reexecute_offset = 0;
|
||||
#ifdef COMPILER1
|
||||
__ b(exec_mode_initialized);
|
||||
|
||||
@ -3068,11 +3066,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
// Return to the interpreter entry point.
|
||||
__ blr();
|
||||
__ flush();
|
||||
#else // COMPILER2
|
||||
#else // !defined(COMPILER1) && !defined(COMPILER2)
|
||||
__ unimplemented("deopt blob needed only with compiler");
|
||||
int exception_offset = __ pc() - start;
|
||||
#endif // COMPILER2
|
||||
#endif
|
||||
|
||||
// Make sure all code is generated
|
||||
__ flush();
|
||||
|
||||
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset,
|
||||
reexecute_offset, first_frame_size_in_bytes / wordSize);
|
||||
|
||||
@ -1041,31 +1041,10 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
|
||||
__ bind(*op->stub()->continuation());
|
||||
}
|
||||
|
||||
void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md, ciProfileData *data,
|
||||
Register recv, Label* update_done) {
|
||||
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
|
||||
Label next_test;
|
||||
// See if the receiver is receiver[n].
|
||||
__ ld(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i))));
|
||||
__ bne(recv, t1, next_test);
|
||||
Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)));
|
||||
__ increment(data_addr, DataLayout::counter_increment);
|
||||
__ j(*update_done);
|
||||
__ bind(next_test);
|
||||
}
|
||||
|
||||
// Didn't find receiver; find next empty slot and fill it in
|
||||
for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) {
|
||||
Label next_test;
|
||||
Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)));
|
||||
__ ld(t1, recv_addr);
|
||||
__ bnez(t1, next_test);
|
||||
__ sd(recv, recv_addr);
|
||||
__ mv(t1, DataLayout::counter_increment);
|
||||
__ sd(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))));
|
||||
__ j(*update_done);
|
||||
__ bind(next_test);
|
||||
}
|
||||
void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md,
|
||||
ciProfileData *data, Register recv) {
|
||||
int mdp_offset = md->byte_offset_of_slot(data, in_ByteSize(0));
|
||||
__ profile_receiver_type(recv, mdo, mdp_offset);
|
||||
}
|
||||
|
||||
void LIR_Assembler::data_check(LIR_OpTypeCheck *op, ciMethodData **md, ciProfileData **data) {
|
||||
@ -1139,14 +1118,9 @@ void LIR_Assembler::profile_object(ciMethodData* md, ciProfileData* data, Regist
|
||||
__ j(*obj_is_null);
|
||||
__ bind(not_null);
|
||||
|
||||
Label update_done;
|
||||
Register recv = k_RInfo;
|
||||
__ load_klass(recv, obj);
|
||||
type_profile_helper(mdo, md, data, recv, &update_done);
|
||||
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
|
||||
__ increment(counter_addr, DataLayout::counter_increment);
|
||||
|
||||
__ bind(update_done);
|
||||
type_profile_helper(mdo, md, data, recv);
|
||||
}
|
||||
|
||||
void LIR_Assembler::typecheck_loaded(LIR_OpTypeCheck *op, ciKlass* k, Register k_RInfo) {
|
||||
@ -1554,11 +1528,8 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
|
||||
// We know the type that will be seen at this call site; we can
|
||||
// statically update the MethodData* rather than needing to do
|
||||
// dynamic tests on the receiver type
|
||||
// NOTE: we should probably put a lock around this search to
|
||||
// avoid collisions by concurrent compilations
|
||||
ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
|
||||
uint i;
|
||||
for (i = 0; i < VirtualCallData::row_limit(); i++) {
|
||||
for (uint i = 0; i < VirtualCallData::row_limit(); i++) {
|
||||
ciKlass* receiver = vc_data->receiver(i);
|
||||
if (known_klass->equals(receiver)) {
|
||||
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
|
||||
@ -1566,32 +1537,13 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver type not found in profile data; select an empty slot
|
||||
// Note that this is less efficient than it should be because it
|
||||
// always does a write to the receiver part of the
|
||||
// VirtualCallData rather than just the first time
|
||||
for (i = 0; i < VirtualCallData::row_limit(); i++) {
|
||||
ciKlass* receiver = vc_data->receiver(i);
|
||||
if (receiver == nullptr) {
|
||||
Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)));
|
||||
__ mov_metadata(t1, known_klass->constant_encoding());
|
||||
__ sd(t1, recv_addr);
|
||||
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
|
||||
__ increment(data_addr, DataLayout::counter_increment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Receiver type is not found in profile data.
|
||||
// Fall back to runtime helper to handle the rest at runtime.
|
||||
__ mov_metadata(recv, known_klass->constant_encoding());
|
||||
} else {
|
||||
__ load_klass(recv, recv);
|
||||
Label update_done;
|
||||
type_profile_helper(mdo, md, data, recv, &update_done);
|
||||
// Receiver did not match any saved receiver and there is no empty row for it.
|
||||
// Increment total counter to indicate polymorphic case.
|
||||
__ increment(counter_addr, DataLayout::counter_increment);
|
||||
|
||||
__ bind(update_done);
|
||||
}
|
||||
type_profile_helper(mdo, md, data, recv);
|
||||
} else {
|
||||
// Static call
|
||||
__ increment(counter_addr, DataLayout::counter_increment);
|
||||
|
||||
@ -54,9 +54,8 @@ private:
|
||||
Address stack_slot_address(int index, uint shift, int adjust = 0);
|
||||
|
||||
// Record the type of the receiver in ReceiverTypeData
|
||||
void type_profile_helper(Register mdo,
|
||||
ciMethodData *md, ciProfileData *data,
|
||||
Register recv, Label* update_done);
|
||||
void type_profile_helper(Register mdo, ciMethodData *md,
|
||||
ciProfileData *data, Register recv);
|
||||
|
||||
void casw(Register addr, Register newval, Register cmpval);
|
||||
void caswu(Register addr, Register newval, Register cmpval);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -2813,10 +2813,14 @@ void C2_MacroAssembler::char_array_compress_v(Register src, Register dst, Regist
|
||||
|
||||
// Intrinsic for
|
||||
//
|
||||
// - sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray
|
||||
// return the number of characters copied.
|
||||
// - java/lang/StringUTF16.compress
|
||||
// return index of non-latin1 character if copy fails, otherwise 'len'.
|
||||
// - sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes char[] to byte[] in ISO-8859-1
|
||||
//
|
||||
// - java.lang.StringCoding#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes byte[] (containing UTF-16) to byte[] in ISO-8859-1
|
||||
//
|
||||
// - java.lang.StringCoding#encodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len)
|
||||
// Encodes char[] to byte[] in ASCII
|
||||
//
|
||||
// This version always returns the number of characters copied. A successful
|
||||
// copy will complete with the post-condition: 'res' == 'len', while an
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap nulls
|
||||
define_pd_global(bool, DelayCompilerStubsGeneration, COMPILER2_OR_JVMCI);
|
||||
|
||||
define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment.
|
||||
define_pd_global(intx, CodeEntryAlignment, 64);
|
||||
define_pd_global(uint, CodeEntryAlignment, 64);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
|
||||
@ -39,7 +39,8 @@ static int icache_flush(address addr, int lines, int magic) {
|
||||
// We need to make sure stores happens before the I/D cache synchronization.
|
||||
__asm__ volatile("fence rw, rw" : : : "memory");
|
||||
|
||||
RiscvFlushIcache::flush((uintptr_t)addr, ((uintptr_t)lines) << ICache::log2_line_size);
|
||||
uintptr_t end = (uintptr_t)addr + ((uintptr_t)lines << ICache::log2_line_size);
|
||||
RiscvFlushIcache::flush((uintptr_t)addr, end);
|
||||
|
||||
return magic;
|
||||
}
|
||||
|
||||
@ -237,15 +237,14 @@ void InterpreterMacroAssembler::load_resolved_klass_at_offset(
|
||||
// Rsub_klass: subklass
|
||||
//
|
||||
// Kills:
|
||||
// x12, x15
|
||||
// x12
|
||||
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
|
||||
Label& ok_is_subtype) {
|
||||
assert(Rsub_klass != x10, "x10 holds superklass");
|
||||
assert(Rsub_klass != x12, "x12 holds 2ndary super array length");
|
||||
assert(Rsub_klass != x15, "x15 holds 2ndary super array scan ptr");
|
||||
|
||||
// Profile the not-null value's klass.
|
||||
profile_typecheck(x12, Rsub_klass, x15); // blows x12, reloads x15
|
||||
profile_typecheck(x12, Rsub_klass); // blows x12
|
||||
|
||||
// Do the check.
|
||||
check_klass_subtype(Rsub_klass, x10, x12, ok_is_subtype); // blows x12
|
||||
@ -1042,7 +1041,6 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) {
|
||||
|
||||
void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
|
||||
Register mdp,
|
||||
Register reg2,
|
||||
bool receiver_can_be_null) {
|
||||
if (ProfileInterpreter) {
|
||||
Label profile_continue;
|
||||
@ -1060,7 +1058,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
|
||||
}
|
||||
|
||||
// Record the receiver type.
|
||||
record_klass_in_profile(receiver, mdp, reg2);
|
||||
profile_receiver_type(receiver, mdp, 0);
|
||||
bind(skip_receiver_profile);
|
||||
|
||||
// The method data pointer needs to be updated to reflect the new target.
|
||||
@ -1072,153 +1070,6 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
|
||||
}
|
||||
}
|
||||
|
||||
// This routine creates a state machine for updating the multi-row
|
||||
// type profile at a virtual call site (or other type-sensitive bytecode).
|
||||
// The machine visits each row (of receiver/count) until the receiver type
|
||||
// is found, or until it runs out of rows. At the same time, it remembers
|
||||
// the location of the first empty row. (An empty row records null for its
|
||||
// receiver, and can be allocated for a newly-observed receiver type.)
|
||||
// Because there are two degrees of freedom in the state, a simple linear
|
||||
// search will not work; it must be a decision tree. Hence this helper
|
||||
// function is recursive, to generate the required tree structured code.
|
||||
// It's the interpreter, so we are trading off code space for speed.
|
||||
// See below for example code.
|
||||
void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
Register receiver, Register mdp,
|
||||
Register reg2, Label& done) {
|
||||
if (TypeProfileWidth == 0) {
|
||||
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
|
||||
} else {
|
||||
record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth,
|
||||
&VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp,
|
||||
Register reg2, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn) {
|
||||
int last_row = total_rows - 1;
|
||||
assert(start_row <= last_row, "must be work left to do");
|
||||
// Test this row for both the item and for null.
|
||||
// Take any of three different outcomes:
|
||||
// 1. found item => increment count and goto done
|
||||
// 2. found null => keep looking for case 1, maybe allocate this cell
|
||||
// 3. found something else => keep looking for cases 1 and 2
|
||||
// Case 3 is handled by a recursive call.
|
||||
for (int row = start_row; row <= last_row; row++) {
|
||||
Label next_test;
|
||||
bool test_for_null_also = (row == start_row);
|
||||
|
||||
// See if the item is item[n].
|
||||
int item_offset = in_bytes(item_offset_fn(row));
|
||||
test_mdp_data_at(mdp, item_offset, item,
|
||||
(test_for_null_also ? reg2 : noreg),
|
||||
next_test);
|
||||
// (Reg2 now contains the item from the CallData.)
|
||||
|
||||
// The item is item[n]. Increment count[n].
|
||||
int count_offset = in_bytes(item_count_offset_fn(row));
|
||||
increment_mdp_data_at(mdp, count_offset);
|
||||
j(done);
|
||||
bind(next_test);
|
||||
|
||||
if (test_for_null_also) {
|
||||
Label found_null;
|
||||
// Failed the equality check on item[n]... Test for null.
|
||||
if (start_row == last_row) {
|
||||
// The only thing left to do is handle the null case.
|
||||
beqz(reg2, found_null);
|
||||
// Item did not match any saved item and there is no empty row for it.
|
||||
// Increment total counter to indicate polymorphic case.
|
||||
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
|
||||
j(done);
|
||||
bind(found_null);
|
||||
break;
|
||||
}
|
||||
// Since null is rare, make it be the branch-taken case.
|
||||
beqz(reg2, found_null);
|
||||
|
||||
// Put all the "Case 3" tests here.
|
||||
record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows,
|
||||
item_offset_fn, item_count_offset_fn);
|
||||
|
||||
// Found a null. Keep searching for a matching item,
|
||||
// but remember that this is an empty (unused) slot.
|
||||
bind(found_null);
|
||||
}
|
||||
}
|
||||
|
||||
// In the fall-through case, we found no matching item, but we
|
||||
// observed the item[start_row] is null.
|
||||
// Fill in the item field and increment the count.
|
||||
int item_offset = in_bytes(item_offset_fn(start_row));
|
||||
set_mdp_data_at(mdp, item_offset, item);
|
||||
int count_offset = in_bytes(item_count_offset_fn(start_row));
|
||||
mv(reg2, DataLayout::counter_increment);
|
||||
set_mdp_data_at(mdp, count_offset, reg2);
|
||||
if (start_row > 0) {
|
||||
j(done);
|
||||
}
|
||||
}
|
||||
|
||||
// Example state machine code for three profile rows:
|
||||
// # main copy of decision tree, rooted at row[1]
|
||||
// if (row[0].rec == rec) then [
|
||||
// row[0].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// if (row[0].rec != nullptr) then [
|
||||
// # inner copy of decision tree, rooted at row[1]
|
||||
// if (row[1].rec == rec) then [
|
||||
// row[1].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// if (row[1].rec != nullptr) then [
|
||||
// # degenerate decision tree, rooted at row[2]
|
||||
// if (row[2].rec == rec) then [
|
||||
// row[2].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// if (row[2].rec != nullptr) then [
|
||||
// count.incr()
|
||||
// goto done
|
||||
// ] # overflow
|
||||
// row[2].init(rec)
|
||||
// goto done
|
||||
// ] else [
|
||||
// # remember row[1] is empty
|
||||
// if (row[2].rec == rec) then [
|
||||
// row[2].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// row[1].init(rec)
|
||||
// goto done
|
||||
// ]
|
||||
// else [
|
||||
// # remember row[0] is empty
|
||||
// if (row[1].rec == rec) then [
|
||||
// row[1].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// if (row[2].rec == rec) then [
|
||||
// row[2].incr()
|
||||
// goto done
|
||||
// ]
|
||||
// row[0].init(rec)
|
||||
// goto done
|
||||
// ]
|
||||
// done:
|
||||
|
||||
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
|
||||
Register mdp, Register reg2) {
|
||||
assert(ProfileInterpreter, "must be profiling");
|
||||
Label done;
|
||||
|
||||
record_klass_in_profile_helper(receiver, mdp, reg2, done);
|
||||
|
||||
bind(done);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_ret(Register return_bci, Register mdp) {
|
||||
if (ProfileInterpreter) {
|
||||
Label profile_continue;
|
||||
@ -1274,7 +1125,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register mdp) {
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) {
|
||||
void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass) {
|
||||
if (ProfileInterpreter) {
|
||||
Label profile_continue;
|
||||
|
||||
@ -1287,7 +1138,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
|
||||
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
|
||||
|
||||
// Record the object type.
|
||||
record_klass_in_profile(klass, mdp, reg2);
|
||||
profile_receiver_type(klass, mdp, 0);
|
||||
}
|
||||
update_mdp_by_constant(mdp, mdp_delta);
|
||||
|
||||
|
||||
@ -262,14 +262,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
Register test_value_out,
|
||||
Label& not_equal_continue);
|
||||
|
||||
void record_klass_in_profile(Register receiver, Register mdp,
|
||||
Register reg2);
|
||||
void record_klass_in_profile_helper(Register receiver, Register mdp,
|
||||
Register reg2, Label& done);
|
||||
void record_item_in_profile_helper(Register item, Register mdp,
|
||||
Register reg2, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn);
|
||||
|
||||
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
|
||||
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
|
||||
void update_mdp_by_constant(Register mdp_in, int constant);
|
||||
@ -283,11 +275,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void profile_call(Register mdp);
|
||||
void profile_final_call(Register mdp);
|
||||
void profile_virtual_call(Register receiver, Register mdp,
|
||||
Register t1,
|
||||
bool receiver_can_be_null = false);
|
||||
void profile_ret(Register return_bci, Register mdp);
|
||||
void profile_null_seen(Register mdp);
|
||||
void profile_typecheck(Register mdp, Register klass, Register temp);
|
||||
void profile_typecheck(Register mdp, Register klass);
|
||||
void profile_typecheck_failed(Register mdp);
|
||||
void profile_switch_default(Register mdp);
|
||||
void profile_switch_case(Register index_in_scratch, Register mdp,
|
||||
|
||||
@ -543,6 +543,160 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
|
||||
BLOCK_COMMENT("} verify_oop");
|
||||
}
|
||||
|
||||
// Handle the receiver type profile update given the "recv" klass.
|
||||
//
|
||||
// Normally updates the ReceiverData (RD) that starts at "mdp" + "mdp_offset".
|
||||
// If there are no matching or claimable receiver entries in RD, updates
|
||||
// the polymorphic counter.
|
||||
//
|
||||
// This code expected to run by either the interpreter or JIT-ed code, without
|
||||
// extra synchronization. For safety, receiver cells are claimed atomically, which
|
||||
// avoids grossly misrepresenting the profiles under concurrent updates. For speed,
|
||||
// counter updates are not atomic.
|
||||
//
|
||||
void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_offset) {
|
||||
assert_different_registers(recv, mdp, t0, t1);
|
||||
|
||||
int base_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(0));
|
||||
int end_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(ReceiverTypeData::row_limit()));
|
||||
int poly_count_offset = in_bytes(CounterData::count_offset());
|
||||
int receiver_step = in_bytes(ReceiverTypeData::receiver_offset(1)) - base_receiver_offset;
|
||||
int receiver_to_count_step = in_bytes(ReceiverTypeData::receiver_count_offset(0)) - base_receiver_offset;
|
||||
|
||||
// Adjust for MDP offsets. Slots are pointer-sized, so is the global offset.
|
||||
base_receiver_offset += mdp_offset;
|
||||
end_receiver_offset += mdp_offset;
|
||||
poly_count_offset += mdp_offset;
|
||||
|
||||
#ifdef ASSERT
|
||||
// We are about to walk the MDO slots without asking for offsets.
|
||||
// Check that our math hits all the right spots.
|
||||
for (uint c = 0; c < ReceiverTypeData::row_limit(); c++) {
|
||||
int real_recv_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_offset(c));
|
||||
int real_count_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_count_offset(c));
|
||||
int offset = base_receiver_offset + receiver_step*c;
|
||||
int count_offset = offset + receiver_to_count_step;
|
||||
assert(offset == real_recv_offset, "receiver slot math");
|
||||
assert(count_offset == real_count_offset, "receiver count math");
|
||||
}
|
||||
int real_poly_count_offset = mdp_offset + in_bytes(CounterData::count_offset());
|
||||
assert(poly_count_offset == real_poly_count_offset, "poly counter math");
|
||||
#endif
|
||||
|
||||
// Corner case: no profile table. Increment poly counter and exit.
|
||||
if (ReceiverTypeData::row_limit() == 0) {
|
||||
increment(Address(mdp, poly_count_offset), DataLayout::counter_increment);
|
||||
return;
|
||||
}
|
||||
|
||||
Register offset = t1;
|
||||
|
||||
Label L_loop_search_receiver, L_loop_search_empty;
|
||||
Label L_restart, L_found_recv, L_found_empty, L_polymorphic, L_count_update;
|
||||
|
||||
// The code here recognizes three major cases:
|
||||
// A. Fastest: receiver found in the table
|
||||
// B. Fast: no receiver in the table, and the table is full
|
||||
// C. Slow: no receiver in the table, free slots in the table
|
||||
//
|
||||
// The case A performance is most important, as perfectly-behaved code would end up
|
||||
// there, especially with larger TypeProfileWidth. The case B performance is
|
||||
// important as well, this is where bulk of code would land for normally megamorphic
|
||||
// cases. The case C performance is not essential, its job is to deal with installation
|
||||
// races, we optimize for code density instead. Case C needs to make sure that receiver
|
||||
// rows are only claimed once. This makes sure we never overwrite a row for another
|
||||
// receiver and never duplicate the receivers in the list, making profile type-accurate.
|
||||
//
|
||||
// It is very tempting to handle these cases in a single loop, and claim the first slot
|
||||
// without checking the rest of the table. But, profiling code should tolerate free slots
|
||||
// in the table, as class unloading can clear them. After such cleanup, the receiver
|
||||
// we need might be _after_ the free slot. Therefore, we need to let at least full scan
|
||||
// to complete, before trying to install new slots. Splitting the code in several tight
|
||||
// loops also helpfully optimizes for cases A and B.
|
||||
//
|
||||
// This code is effectively:
|
||||
//
|
||||
// restart:
|
||||
// // Fastest: receiver is already installed
|
||||
// for (i = 0; i < receiver_count(); i++) {
|
||||
// if (receiver(i) == recv) goto found_recv(i);
|
||||
// }
|
||||
//
|
||||
// // Fast: no receiver, but profile is full
|
||||
// for (i = 0; i < receiver_count(); i++) {
|
||||
// if (receiver(i) == null) goto found_null(i);
|
||||
// }
|
||||
// goto polymorphic
|
||||
//
|
||||
// // Slow: try to install receiver
|
||||
// found_null(i):
|
||||
// CAS(&receiver(i), null, recv);
|
||||
// goto restart
|
||||
//
|
||||
// polymorphic:
|
||||
// count++;
|
||||
// return
|
||||
//
|
||||
// found_recv(i):
|
||||
// *receiver_count(i)++
|
||||
//
|
||||
|
||||
bind(L_restart);
|
||||
|
||||
// Fastest: receiver is already installed
|
||||
mv(offset, base_receiver_offset);
|
||||
bind(L_loop_search_receiver);
|
||||
add(t0, mdp, offset);
|
||||
ld(t0, Address(t0));
|
||||
beq(recv, t0, L_found_recv);
|
||||
add(offset, offset, receiver_step);
|
||||
sub(t0, offset, end_receiver_offset);
|
||||
bnez(t0, L_loop_search_receiver);
|
||||
|
||||
// Fast: no receiver, but profile is full
|
||||
mv(offset, base_receiver_offset);
|
||||
bind(L_loop_search_empty);
|
||||
add(t0, mdp, offset);
|
||||
ld(t0, Address(t0));
|
||||
beqz(t0, L_found_empty);
|
||||
add(offset, offset, receiver_step);
|
||||
sub(t0, offset, end_receiver_offset);
|
||||
bnez(t0, L_loop_search_empty);
|
||||
j(L_polymorphic);
|
||||
|
||||
// Slow: try to install receiver
|
||||
bind(L_found_empty);
|
||||
|
||||
// Atomically swing receiver slot: null -> recv.
|
||||
//
|
||||
// The update uses CAS, which clobbers t0. Therefore, t1
|
||||
// is used to hold the destination address. This is safe because the
|
||||
// offset is no longer needed after the address is computed.
|
||||
add(t1, mdp, offset);
|
||||
weak_cmpxchg(/*addr*/ t1, /*expected*/ zr, /*new*/ recv, Assembler::int64,
|
||||
/*acquire*/ Assembler::relaxed, /*release*/ Assembler::relaxed, /*result*/ t0);
|
||||
|
||||
// CAS success means the slot now has the receiver we want. CAS failure means
|
||||
// something had claimed the slot concurrently: it can be the same receiver we want,
|
||||
// or something else. Since this is a slow path, we can optimize for code density,
|
||||
// and just restart the search from the beginning.
|
||||
j(L_restart);
|
||||
|
||||
// Counter updates:
|
||||
// Increment polymorphic counter instead of receiver slot.
|
||||
bind(L_polymorphic);
|
||||
mv(offset, poly_count_offset);
|
||||
j(L_count_update);
|
||||
|
||||
// Found a receiver, convert its slot offset to corresponding count offset.
|
||||
bind(L_found_recv);
|
||||
add(offset, offset, receiver_to_count_step);
|
||||
|
||||
bind(L_count_update);
|
||||
add(t1, mdp, offset);
|
||||
increment(Address(t1), DataLayout::counter_increment);
|
||||
}
|
||||
|
||||
void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* file, int line) {
|
||||
if (!VerifyOops) {
|
||||
return;
|
||||
|
||||
@ -390,6 +390,8 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
|
||||
|
||||
void profile_receiver_type(Register recv, Register mdp, int mdp_offset);
|
||||
|
||||
// only if +VerifyOops
|
||||
void _verify_oop(Register reg, const char* s, const char* file, int line);
|
||||
void _verify_oop_addr(Address addr, const char* s, const char* file, int line);
|
||||
|
||||
@ -3279,7 +3279,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
||||
__ load_klass(x10, recv);
|
||||
|
||||
// profile this call
|
||||
__ profile_virtual_call(x10, xlocals, x13);
|
||||
__ profile_virtual_call(x10, xlocals);
|
||||
|
||||
// get target Method & entry point
|
||||
__ lookup_virtual_method(x10, index, method);
|
||||
@ -3406,7 +3406,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
/*return_method=*/false);
|
||||
|
||||
// profile this call
|
||||
__ profile_virtual_call(x13, x30, x9);
|
||||
__ profile_virtual_call(x13, x30);
|
||||
|
||||
// Get declaring interface class from method, and itable index
|
||||
__ load_method_holder(x10, xmethod);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -129,6 +129,57 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
|
||||
__ block_comment("generate_post_barrier {");
|
||||
|
||||
assert(thread == Z_thread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
|
||||
// Does store cross heap regions?
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
__ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
} else {
|
||||
__ z_lgr(tmp1, store_addr);
|
||||
__ z_xgr(tmp1, new_val);
|
||||
}
|
||||
__ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ branch_optimized(Assembler::bcondEqual, done);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (new_val_may_be_null) {
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ z_bre(done);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
|
||||
#endif
|
||||
}
|
||||
|
||||
__ z_srag(tmp1, store_addr, CardTable::card_shift());
|
||||
|
||||
Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
|
||||
__ z_alg(tmp1, card_table_addr); // tmp1 := card address
|
||||
|
||||
if(UseCondCardMark) {
|
||||
__ z_cli(0, tmp1, G1CardTable::clean_card_val());
|
||||
__ branch_optimized(Assembler::bcondNotEqual, done);
|
||||
}
|
||||
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
|
||||
__ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
|
||||
|
||||
__ block_comment("} generate_post_barrier");
|
||||
}
|
||||
|
||||
#if defined(COMPILER2)
|
||||
|
||||
#undef __
|
||||
@ -204,57 +255,6 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
|
||||
BLOCK_COMMENT("} generate_c2_pre_barrier_stub");
|
||||
}
|
||||
|
||||
static void generate_post_barrier(MacroAssembler* masm,
|
||||
const Register store_addr,
|
||||
const Register new_val,
|
||||
const Register thread,
|
||||
const Register tmp1,
|
||||
const Register tmp2,
|
||||
Label& done,
|
||||
bool new_val_may_be_null) {
|
||||
|
||||
__ block_comment("generate_post_barrier {");
|
||||
|
||||
assert(thread == Z_thread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
|
||||
// Does store cross heap regions?
|
||||
if (VM_Version::has_DistinctOpnds()) {
|
||||
__ z_xgrk(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
} else {
|
||||
__ z_lgr(tmp1, store_addr);
|
||||
__ z_xgr(tmp1, new_val);
|
||||
}
|
||||
__ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ branch_optimized(Assembler::bcondEqual, done);
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (new_val_may_be_null) {
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ z_bre(done);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
__ z_ltgr(new_val, new_val);
|
||||
__ asm_assert(Assembler::bcondNotZero, "null oop not allowed (G1 post)", 0x322); // Checked by caller.
|
||||
#endif
|
||||
}
|
||||
|
||||
__ z_srag(tmp1, store_addr, CardTable::card_shift());
|
||||
|
||||
Address card_table_addr(thread, in_bytes(G1ThreadLocalData::card_table_base_offset()));
|
||||
__ z_alg(tmp1, card_table_addr); // tmp1 := card address
|
||||
|
||||
if(UseCondCardMark) {
|
||||
__ z_cli(0, tmp1, G1CardTable::clean_card_val());
|
||||
__ branch_optimized(Assembler::bcondNotEqual, done);
|
||||
}
|
||||
|
||||
static_assert(G1CardTable::dirty_card_val() == 0, "must be to use z_mvi");
|
||||
__ z_mvi(0, tmp1, G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
|
||||
|
||||
__ block_comment("} generate_post_barrier");
|
||||
}
|
||||
|
||||
void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
|
||||
Register store_addr,
|
||||
Register new_val,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -43,7 +43,7 @@ define_pd_global(size_t, CodeCacheSegmentSize, 256);
|
||||
// Ideally, this is 256 (cache line size). This keeps code end data
|
||||
// on separate lines. But we reduced it to 64 since 256 increased
|
||||
// code size significantly by padding nops between IVC and second UEP.
|
||||
define_pd_global(intx, CodeEntryAlignment, 64);
|
||||
define_pd_global(uint, CodeEntryAlignment, 64);
|
||||
define_pd_global(intx, OptoLoopAlignment, 2);
|
||||
define_pd_global(intx, InlineSmallCode, 2000);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, 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
|
||||
@ -7320,6 +7320,25 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
|
||||
emit_int16(0x2E, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vucomxsd(XMMRegister dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8(0x2E);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::vucomxsd(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
|
||||
emit_int16(0x2E, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::ucomiss(XMMRegister dst, Address src) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
@ -7335,6 +7354,25 @@ void Assembler::ucomiss(XMMRegister dst, XMMRegister src) {
|
||||
emit_int16(0x2E, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vucomxss(XMMRegister dst, Address src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
|
||||
attributes.set_is_evex_instruction();
|
||||
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8(0x2E);
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::vucomxss(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_avx10_2(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
|
||||
attributes.set_is_evex_instruction();
|
||||
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
|
||||
emit_int16(0x2E, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::xabort(int8_t imm8) {
|
||||
emit_int24((unsigned char)0xC6, (unsigned char)0xF8, (imm8 & 0xFF));
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, 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
|
||||
@ -2331,10 +2331,14 @@ private:
|
||||
// Unordered Compare Scalar Double-Precision Floating-Point Values and set EFLAGS
|
||||
void ucomisd(XMMRegister dst, Address src);
|
||||
void ucomisd(XMMRegister dst, XMMRegister src);
|
||||
void vucomxsd(XMMRegister dst, Address src);
|
||||
void vucomxsd(XMMRegister dst, XMMRegister src);
|
||||
|
||||
// Unordered Compare Scalar Single-Precision Floating-Point Values and set EFLAGS
|
||||
void ucomiss(XMMRegister dst, Address src);
|
||||
void ucomiss(XMMRegister dst, XMMRegister src);
|
||||
void vucomxss(XMMRegister dst, Address src);
|
||||
void vucomxss(XMMRegister dst, XMMRegister src);
|
||||
|
||||
void xabort(int8_t imm8);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, 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
|
||||
@ -1046,17 +1046,28 @@ void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero,
|
||||
|
||||
Label DONE_LABEL;
|
||||
|
||||
// Handle special cases +0.0/-0.0 and NaN, if argument is +0.0/-0.0 or NaN, return argument
|
||||
// If AVX10.2 (or newer) floating point comparison instructions used, SF=1 for equal and unordered cases
|
||||
// If other floating point comparison instructions used, ZF=1 for equal and unordered cases
|
||||
if (opcode == Op_SignumF) {
|
||||
ucomiss(dst, zero);
|
||||
jcc(Assembler::equal, DONE_LABEL); // handle special case +0.0/-0.0, if argument is +0.0/-0.0, return argument
|
||||
jcc(Assembler::parity, DONE_LABEL); // handle special case NaN, if argument NaN, return NaN
|
||||
if (VM_Version::supports_avx10_2()) {
|
||||
vucomxss(dst, zero);
|
||||
jcc(Assembler::negative, DONE_LABEL);
|
||||
} else {
|
||||
ucomiss(dst, zero);
|
||||
jcc(Assembler::equal, DONE_LABEL);
|
||||
}
|
||||
movflt(dst, one);
|
||||
jcc(Assembler::above, DONE_LABEL);
|
||||
xorps(dst, ExternalAddress(StubRoutines::x86::vector_float_sign_flip()), noreg);
|
||||
} else if (opcode == Op_SignumD) {
|
||||
ucomisd(dst, zero);
|
||||
jcc(Assembler::equal, DONE_LABEL); // handle special case +0.0/-0.0, if argument is +0.0/-0.0, return argument
|
||||
jcc(Assembler::parity, DONE_LABEL); // handle special case NaN, if argument NaN, return NaN
|
||||
if (VM_Version::supports_avx10_2()) {
|
||||
vucomxsd(dst, zero);
|
||||
jcc(Assembler::negative, DONE_LABEL);
|
||||
} else {
|
||||
ucomisd(dst, zero);
|
||||
jcc(Assembler::equal, DONE_LABEL);
|
||||
}
|
||||
movdbl(dst, one);
|
||||
jcc(Assembler::above, DONE_LABEL);
|
||||
xorpd(dst, ExternalAddress(StubRoutines::x86::vector_double_sign_flip()), noreg);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, 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
|
||||
@ -46,9 +46,9 @@ define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRES
|
||||
// the uep and the vep doesn't get real alignment but just slops on by
|
||||
// only assured that the entry instruction meets the 5 byte size requirement.
|
||||
#if COMPILER2_OR_JVMCI
|
||||
define_pd_global(intx, CodeEntryAlignment, 32);
|
||||
define_pd_global(uint, CodeEntryAlignment, 32);
|
||||
#else
|
||||
define_pd_global(intx, CodeEntryAlignment, 16);
|
||||
define_pd_global(uint, CodeEntryAlignment, 16);
|
||||
#endif // COMPILER2_OR_JVMCI
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
|
||||
@ -765,7 +765,7 @@ void MacroAssembler::align32() {
|
||||
|
||||
void MacroAssembler::align(uint modulus) {
|
||||
// 8273459: Ensure alignment is possible with current segment alignment
|
||||
assert(modulus <= (uintx)CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment");
|
||||
assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment");
|
||||
align(modulus, offset());
|
||||
}
|
||||
|
||||
@ -2656,6 +2656,17 @@ void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src, Register rscra
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::vucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch) {
|
||||
assert(rscratch != noreg || always_reachable(src), "missing");
|
||||
|
||||
if (reachable(src)) {
|
||||
Assembler::vucomxsd(dst, as_Address(src));
|
||||
} else {
|
||||
lea(rscratch, src);
|
||||
Assembler::vucomxsd(dst, Address(rscratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src, Register rscratch) {
|
||||
assert(rscratch != noreg || always_reachable(src), "missing");
|
||||
|
||||
@ -2667,6 +2678,17 @@ void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src, Register rscra
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::vucomxss(XMMRegister dst, AddressLiteral src, Register rscratch) {
|
||||
assert(rscratch != noreg || always_reachable(src), "missing");
|
||||
|
||||
if (reachable(src)) {
|
||||
Assembler::vucomxss(dst, as_Address(src));
|
||||
} else {
|
||||
lea(rscratch, src);
|
||||
Assembler::vucomxss(dst, Address(rscratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::xorpd(XMMRegister dst, AddressLiteral src, Register rscratch) {
|
||||
assert(rscratch != noreg || always_reachable(src), "missing");
|
||||
|
||||
@ -6251,32 +6273,46 @@ void MacroAssembler::evpbroadcast(BasicType type, XMMRegister dst, Register src,
|
||||
}
|
||||
}
|
||||
|
||||
// encode char[] to byte[] in ISO_8859_1 or ASCII
|
||||
//@IntrinsicCandidate
|
||||
//private static int implEncodeISOArray(byte[] sa, int sp,
|
||||
//byte[] da, int dp, int len) {
|
||||
// int i = 0;
|
||||
// for (; i < len; i++) {
|
||||
// char c = StringUTF16.getChar(sa, sp++);
|
||||
// if (c > '\u00FF')
|
||||
// break;
|
||||
// da[dp++] = (byte)c;
|
||||
// }
|
||||
// return i;
|
||||
//}
|
||||
//
|
||||
//@IntrinsicCandidate
|
||||
//private static int implEncodeAsciiArray(char[] sa, int sp,
|
||||
// byte[] da, int dp, int len) {
|
||||
// int i = 0;
|
||||
// for (; i < len; i++) {
|
||||
// char c = sa[sp++];
|
||||
// if (c >= '\u0080')
|
||||
// break;
|
||||
// da[dp++] = (byte)c;
|
||||
// }
|
||||
// return i;
|
||||
//}
|
||||
// Encode given char[]/byte[] to byte[] in ISO_8859_1 or ASCII
|
||||
//
|
||||
// @IntrinsicCandidate
|
||||
// int sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(
|
||||
// char[] sa, int sp, byte[] da, int dp, int len) {
|
||||
// int i = 0;
|
||||
// for (; i < len; i++) {
|
||||
// char c = sa[sp++];
|
||||
// if (c > '\u00FF')
|
||||
// break;
|
||||
// da[dp++] = (byte) c;
|
||||
// }
|
||||
// return i;
|
||||
// }
|
||||
//
|
||||
// @IntrinsicCandidate
|
||||
// int java.lang.StringCoding.encodeISOArray0(
|
||||
// byte[] sa, int sp, byte[] da, int dp, int len) {
|
||||
// int i = 0;
|
||||
// for (; i < len; i++) {
|
||||
// char c = StringUTF16.getChar(sa, sp++);
|
||||
// if (c > '\u00FF')
|
||||
// break;
|
||||
// da[dp++] = (byte) c;
|
||||
// }
|
||||
// return i;
|
||||
// }
|
||||
//
|
||||
// @IntrinsicCandidate
|
||||
// int java.lang.StringCoding.encodeAsciiArray0(
|
||||
// char[] sa, int sp, byte[] da, int dp, int len) {
|
||||
// int i = 0;
|
||||
// for (; i < len; i++) {
|
||||
// char c = sa[sp++];
|
||||
// if (c >= '\u0080')
|
||||
// break;
|
||||
// da[dp++] = (byte) c;
|
||||
// }
|
||||
// return i;
|
||||
// }
|
||||
void MacroAssembler::encode_iso_array(Register src, Register dst, Register len,
|
||||
XMMRegister tmp1Reg, XMMRegister tmp2Reg,
|
||||
XMMRegister tmp3Reg, XMMRegister tmp4Reg,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, 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
|
||||
@ -1313,10 +1313,18 @@ public:
|
||||
void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); }
|
||||
void ucomiss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
|
||||
|
||||
void vucomxss(XMMRegister dst, XMMRegister src) { Assembler::vucomxss(dst, src); }
|
||||
void vucomxss(XMMRegister dst, Address src) { Assembler::vucomxss(dst, src); }
|
||||
void vucomxss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
|
||||
|
||||
void ucomisd(XMMRegister dst, XMMRegister src) { Assembler::ucomisd(dst, src); }
|
||||
void ucomisd(XMMRegister dst, Address src) { Assembler::ucomisd(dst, src); }
|
||||
void ucomisd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
|
||||
|
||||
void vucomxsd(XMMRegister dst, XMMRegister src) { Assembler::vucomxsd(dst, src); }
|
||||
void vucomxsd(XMMRegister dst, Address src) { Assembler::vucomxsd(dst, src); }
|
||||
void vucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
|
||||
|
||||
// Bitwise Logical XOR of Packed Double-Precision Floating-Point Values
|
||||
void xorpd(XMMRegister dst, XMMRegister src);
|
||||
void xorpd(XMMRegister dst, Address src) { Assembler::xorpd(dst, src); }
|
||||
|
||||
@ -1152,6 +1152,10 @@ void VM_Version::get_processor_features() {
|
||||
warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
|
||||
if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
} else {
|
||||
if (UseSSE > 2) {
|
||||
if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||
@ -1170,8 +1174,8 @@ void VM_Version::get_processor_features() {
|
||||
if (!UseAESIntrinsics) {
|
||||
if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled.");
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
} else {
|
||||
if (supports_sse4_1()) {
|
||||
if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
@ -1191,16 +1195,16 @@ void VM_Version::get_processor_features() {
|
||||
} else if (UseAES || UseAESIntrinsics || UseAESCTRIntrinsics) {
|
||||
if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
|
||||
warning("AES instructions are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseAES, false);
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAES, false);
|
||||
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||
warning("AES intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
|
||||
if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
warning("AES-CTR intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
}
|
||||
|
||||
// Use CLMUL instructions if available.
|
||||
@ -1355,16 +1359,16 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (supports_evex() && supports_avx512bw()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
UseSHA3Intrinsics = true;
|
||||
}
|
||||
if (UseSHA && supports_evex() && supports_avx512bw()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA3Intrinsics) {
|
||||
warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
|
||||
warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
|
||||
}
|
||||
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics || UseSHA3Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
@ -1655,41 +1659,40 @@ void VM_Version::get_processor_features() {
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) {
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3);
|
||||
}
|
||||
#ifdef COMPILER2
|
||||
if (UseAVX > 2) {
|
||||
if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) ||
|
||||
(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) &&
|
||||
ArrayOperationPartialInlineSize != 0 &&
|
||||
ArrayOperationPartialInlineSize != 16 &&
|
||||
ArrayOperationPartialInlineSize != 32 &&
|
||||
ArrayOperationPartialInlineSize != 64)) {
|
||||
int inline_size = 0;
|
||||
if (MaxVectorSize >= 64 && AVX3Threshold == 0) {
|
||||
inline_size = 64;
|
||||
} else if (MaxVectorSize >= 32) {
|
||||
inline_size = 32;
|
||||
} else if (MaxVectorSize >= 16) {
|
||||
inline_size = 16;
|
||||
}
|
||||
if(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) {
|
||||
warning("Setting ArrayOperationPartialInlineSize as %d", inline_size);
|
||||
}
|
||||
ArrayOperationPartialInlineSize = inline_size;
|
||||
}
|
||||
|
||||
if (ArrayOperationPartialInlineSize > MaxVectorSize) {
|
||||
ArrayOperationPartialInlineSize = MaxVectorSize >= 16 ? MaxVectorSize : 0;
|
||||
if (ArrayOperationPartialInlineSize) {
|
||||
warning("Setting ArrayOperationPartialInlineSize as MaxVectorSize=%zd", MaxVectorSize);
|
||||
} else {
|
||||
warning("Setting ArrayOperationPartialInlineSize as %zd", ArrayOperationPartialInlineSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (UseAVX > 2) {
|
||||
if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) ||
|
||||
(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize) &&
|
||||
ArrayOperationPartialInlineSize != 0 &&
|
||||
ArrayOperationPartialInlineSize != 16 &&
|
||||
ArrayOperationPartialInlineSize != 32 &&
|
||||
ArrayOperationPartialInlineSize != 64)) {
|
||||
int inline_size = 0;
|
||||
if (MaxVectorSize >= 64 && AVX3Threshold == 0) {
|
||||
inline_size = 64;
|
||||
} else if (MaxVectorSize >= 32) {
|
||||
inline_size = 32;
|
||||
} else if (MaxVectorSize >= 16) {
|
||||
inline_size = 16;
|
||||
}
|
||||
if(!FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) {
|
||||
warning("Setting ArrayOperationPartialInlineSize as %d", inline_size);
|
||||
}
|
||||
ArrayOperationPartialInlineSize = inline_size;
|
||||
}
|
||||
|
||||
if (ArrayOperationPartialInlineSize > MaxVectorSize) {
|
||||
ArrayOperationPartialInlineSize = MaxVectorSize >= 16 ? MaxVectorSize : 0;
|
||||
if (ArrayOperationPartialInlineSize) {
|
||||
warning("Setting ArrayOperationPartialInlineSize as MaxVectorSize=%zd", MaxVectorSize);
|
||||
} else {
|
||||
warning("Setting ArrayOperationPartialInlineSize as %zd", ArrayOperationPartialInlineSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(OptimizeFill)) {
|
||||
if (MaxVectorSize < 32 || (!EnableX86ECoreOpts && !VM_Version::supports_avx512vlbw())) {
|
||||
OptimizeFill = false;
|
||||
|
||||
@ -1699,9 +1699,10 @@ static void emit_cmpfp_fixup(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
static void emit_cmpfp3(MacroAssembler* masm, Register dst) {
|
||||
// If any floating point comparison instruction is used, unordered case always triggers jump
|
||||
// for below condition, CF=1 is true when at least one input is NaN
|
||||
Label done;
|
||||
__ movl(dst, -1);
|
||||
__ jcc(Assembler::parity, done);
|
||||
__ jcc(Assembler::below, done);
|
||||
__ setcc(Assembler::notEqual, dst);
|
||||
__ bind(done);
|
||||
@ -5529,12 +5530,21 @@ operand rFlagsRegU()
|
||||
operand rFlagsRegUCF() %{
|
||||
constraint(ALLOC_IN_RC(int_flags));
|
||||
match(RegFlags);
|
||||
predicate(false);
|
||||
predicate(!UseAPX || !VM_Version::supports_avx10_2());
|
||||
|
||||
format %{ "RFLAGS_U_CF" %}
|
||||
interface(REG_INTER);
|
||||
%}
|
||||
|
||||
operand rFlagsRegUCFE() %{
|
||||
constraint(ALLOC_IN_RC(int_flags));
|
||||
match(RegFlags);
|
||||
predicate(UseAPX && VM_Version::supports_avx10_2());
|
||||
|
||||
format %{ "RFLAGS_U_CFE" %}
|
||||
interface(REG_INTER);
|
||||
%}
|
||||
|
||||
// Float register operands
|
||||
operand regF() %{
|
||||
constraint(ALLOC_IN_RC(float_reg));
|
||||
@ -6027,10 +6037,10 @@ operand cmpOp()
|
||||
interface(COND_INTER) %{
|
||||
equal(0x4, "e");
|
||||
not_equal(0x5, "ne");
|
||||
less(0xC, "l");
|
||||
greater_equal(0xD, "ge");
|
||||
less_equal(0xE, "le");
|
||||
greater(0xF, "g");
|
||||
less(0xc, "l");
|
||||
greater_equal(0xd, "ge");
|
||||
less_equal(0xe, "le");
|
||||
greater(0xf, "g");
|
||||
overflow(0x0, "o");
|
||||
no_overflow(0x1, "no");
|
||||
%}
|
||||
@ -6062,11 +6072,12 @@ operand cmpOpU()
|
||||
// don't need to use cmpOpUCF2 for eq/ne
|
||||
operand cmpOpUCF() %{
|
||||
match(Bool);
|
||||
predicate(n->as_Bool()->_test._test == BoolTest::lt ||
|
||||
n->as_Bool()->_test._test == BoolTest::ge ||
|
||||
n->as_Bool()->_test._test == BoolTest::le ||
|
||||
n->as_Bool()->_test._test == BoolTest::gt ||
|
||||
n->in(1)->in(1) == n->in(1)->in(2));
|
||||
predicate((!UseAPX || !VM_Version::supports_avx10_2()) &&
|
||||
(n->as_Bool()->_test._test == BoolTest::lt ||
|
||||
n->as_Bool()->_test._test == BoolTest::ge ||
|
||||
n->as_Bool()->_test._test == BoolTest::le ||
|
||||
n->as_Bool()->_test._test == BoolTest::gt ||
|
||||
n->in(1)->in(1) == n->in(1)->in(2)));
|
||||
format %{ "" %}
|
||||
interface(COND_INTER) %{
|
||||
equal(0xb, "np");
|
||||
@ -6084,7 +6095,8 @@ operand cmpOpUCF() %{
|
||||
// Floating comparisons that can be fixed up with extra conditional jumps
|
||||
operand cmpOpUCF2() %{
|
||||
match(Bool);
|
||||
predicate((n->as_Bool()->_test._test == BoolTest::ne ||
|
||||
predicate((!UseAPX || !VM_Version::supports_avx10_2()) &&
|
||||
(n->as_Bool()->_test._test == BoolTest::ne ||
|
||||
n->as_Bool()->_test._test == BoolTest::eq) &&
|
||||
n->in(1)->in(1) != n->in(1)->in(2));
|
||||
format %{ "" %}
|
||||
@ -6100,6 +6112,37 @@ operand cmpOpUCF2() %{
|
||||
%}
|
||||
%}
|
||||
|
||||
|
||||
// Floating point comparisons that set condition flags to test more directly,
|
||||
// Unsigned tests are used for G (>) and GE (>=) conditions while signed tests
|
||||
// are used for L (<) and LE (<=) conditions. It's important to convert these
|
||||
// latter conditions to ones that use unsigned tests before passing into an
|
||||
// instruction because the preceding comparison might be based on a three way
|
||||
// comparison (CmpF3 or CmpD3) that also assigns unordered outcomes to -1.
|
||||
operand cmpOpUCFE()
|
||||
%{
|
||||
match(Bool);
|
||||
predicate((UseAPX && VM_Version::supports_avx10_2()) &&
|
||||
(n->as_Bool()->_test._test == BoolTest::ne ||
|
||||
n->as_Bool()->_test._test == BoolTest::eq ||
|
||||
n->as_Bool()->_test._test == BoolTest::lt ||
|
||||
n->as_Bool()->_test._test == BoolTest::ge ||
|
||||
n->as_Bool()->_test._test == BoolTest::le ||
|
||||
n->as_Bool()->_test._test == BoolTest::gt));
|
||||
|
||||
format %{ "" %}
|
||||
interface(COND_INTER) %{
|
||||
equal(0x4, "e");
|
||||
not_equal(0x5, "ne");
|
||||
less(0x2, "b");
|
||||
greater_equal(0x3, "ae");
|
||||
less_equal(0x6, "be");
|
||||
greater(0x7, "a");
|
||||
overflow(0x0, "o");
|
||||
no_overflow(0x1, "no");
|
||||
%}
|
||||
%}
|
||||
|
||||
// Operands for bound floating pointer register arguments
|
||||
operand rxmm0() %{
|
||||
constraint(ALLOC_IN_RC(xmm0_reg));
|
||||
@ -9116,20 +9159,34 @@ instruct cmovI_imm_01UCF(rRegI dst, immI_1 src, rFlagsRegUCF cr, cmpOpUCF cop)
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct cmovI_imm_01UCFE(rRegI dst, immI_1 src, rFlagsRegUCFE cr, cmpOpUCFE cop)
|
||||
%{
|
||||
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src dst)));
|
||||
|
||||
ins_cost(100); // XXX
|
||||
format %{ "setbn$cop $dst\t# signed, unsigned, int" %}
|
||||
ins_encode %{
|
||||
Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode);
|
||||
__ setb(MacroAssembler::negate_condition(cond), $dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovI_regU(cop, cr, dst, src);
|
||||
%}
|
||||
%}
|
||||
|
||||
instruct cmovI_regUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, rRegI src2) %{
|
||||
predicate(UseAPX);
|
||||
instruct cmovI_regUCFE_ndd(rRegI dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegI src1, rRegI src2) %{
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2)));
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %}
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, unsigned, int ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
@ -9137,7 +9194,7 @@ instruct cmovI_regUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1,
|
||||
%}
|
||||
|
||||
instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
@ -9150,25 +9207,10 @@ instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovI_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpl $dst, $src1, $src2\n\t"
|
||||
"cmovnel $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||
// inputs of the CMove
|
||||
instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src dst)));
|
||||
effect(TEMP dst);
|
||||
|
||||
@ -9182,23 +9224,6 @@ instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
// We need this special handling for only eq / neq comparison since NaN == NaN is false,
|
||||
// and parity flag bit is set if any of the operand is a NaN.
|
||||
instruct cmovI_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src2 src1)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpl $dst, $src1, $src2\n\t"
|
||||
"cmovnel $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
// Conditional move
|
||||
instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{
|
||||
predicate(!UseAPX);
|
||||
@ -9241,8 +9266,8 @@ instruct cmovI_memU(cmpOpU cop, rFlagsRegU cr, rRegI dst, memory src)
|
||||
%}
|
||||
|
||||
instruct cmovI_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, memory src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src))));
|
||||
|
||||
ins_cost(250);
|
||||
expand %{
|
||||
cmovI_memU(cop, cr, dst, src);
|
||||
@ -9262,12 +9287,12 @@ instruct cmovI_rReg_rReg_memU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI sr
|
||||
ins_pipe(pipe_cmov_mem);
|
||||
%}
|
||||
|
||||
instruct cmovI_rReg_rReg_memUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, memory src2)
|
||||
instruct cmovI_rReg_rReg_memUCFE_ndd(rRegI dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegI src1, memory src2)
|
||||
%{
|
||||
predicate(UseAPX);
|
||||
match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2))));
|
||||
|
||||
ins_cost(250);
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %}
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, unsigned, int ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address);
|
||||
%}
|
||||
@ -9317,8 +9342,8 @@ instruct cmovN_regU(cmpOpU cop, rFlagsRegU cr, rRegN dst, rRegN src)
|
||||
%}
|
||||
|
||||
instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveN (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovN_regU(cop, cr, dst, src);
|
||||
@ -9339,11 +9364,11 @@ instruct cmovN_regU_ndd(rRegN dst, cmpOpU cop, rFlagsRegU cr, rRegN src1, rRegN
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovN_regUCF_ndd(rRegN dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegN src1, rRegN src2) %{
|
||||
predicate(UseAPX);
|
||||
instruct cmovN_regUCFE_ndd(rRegN dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegN src1, rRegN src2) %{
|
||||
match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2)));
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, compressed ptr ndd" %}
|
||||
format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, unsigned, compressed ptr ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
@ -9437,19 +9462,19 @@ instruct cmovP_regU_ndd(rRegP dst, cmpOpU cop, rFlagsRegU cr, rRegP src1, rRegP
|
||||
%}
|
||||
|
||||
instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovP_regU(cop, cr, dst, src);
|
||||
%}
|
||||
%}
|
||||
|
||||
instruct cmovP_regUCF_ndd(rRegP dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegP src1, rRegP src2) %{
|
||||
predicate(UseAPX);
|
||||
instruct cmovP_regUCFE_ndd(rRegP dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegP src1, rRegP src2) %{
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2)));
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %}
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, unsigned, ptr ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
@ -9457,7 +9482,7 @@ instruct cmovP_regUCF_ndd(rRegP dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegP src1,
|
||||
%}
|
||||
|
||||
instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
@ -9470,25 +9495,10 @@ instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovP_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpq $dst, $src1, $src2\n\t"
|
||||
"cmovneq $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||
// inputs of the CMove
|
||||
instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary src dst)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
@ -9501,21 +9511,6 @@ instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovP_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveP (Binary cop cr) (Binary src2 src1)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpq $dst, $src1, $src2\n\t"
|
||||
"cmovneq $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_imm_01(rRegL dst, immL1 src, rFlagsReg cr, cmpOp cop)
|
||||
%{
|
||||
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0);
|
||||
@ -9636,21 +9631,35 @@ instruct cmovL_imm_01UCF(rRegL dst, immL1 src, rFlagsRegUCF cr, cmpOpUCF cop)
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_imm_01UCFE(rRegL dst, immL1 src, rFlagsRegUCFE cr, cmpOpUCFE cop)
|
||||
%{
|
||||
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
|
||||
|
||||
ins_cost(100); // XXX
|
||||
format %{ "setbn$cop $dst\t# signed, unsigned, long" %}
|
||||
ins_encode %{
|
||||
Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode);
|
||||
__ setb(MacroAssembler::negate_condition(cond), $dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovL_regU(cop, cr, dst, src);
|
||||
%}
|
||||
%}
|
||||
|
||||
instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, rRegL src2)
|
||||
instruct cmovL_regUCFE_ndd(rRegL dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegL src1, rRegL src2)
|
||||
%{
|
||||
predicate(UseAPX);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2)));
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %}
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, unsigned, long ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
%}
|
||||
@ -9658,7 +9667,7 @@ instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1,
|
||||
%}
|
||||
|
||||
instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
@ -9671,25 +9680,10 @@ instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpq $dst, $src1, $src2\n\t"
|
||||
"cmovneq $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the
|
||||
// inputs of the CMove
|
||||
instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
|
||||
predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
@ -9702,21 +9696,6 @@ instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src)
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{
|
||||
predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src2 src1)));
|
||||
effect(TEMP dst);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovpq $dst, $src1, $src2\n\t"
|
||||
"cmovneq $dst, $src2" %}
|
||||
ins_encode %{
|
||||
__ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register);
|
||||
__ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_cmov_reg);
|
||||
%}
|
||||
|
||||
instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src)
|
||||
%{
|
||||
predicate(!UseAPX);
|
||||
@ -9731,8 +9710,8 @@ instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src)
|
||||
%}
|
||||
|
||||
instruct cmovL_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, memory src) %{
|
||||
predicate(!UseAPX);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src))));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovL_memU(cop, cr, dst, src);
|
||||
@ -9752,12 +9731,12 @@ instruct cmovL_rReg_rReg_memU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL sr
|
||||
ins_pipe(pipe_cmov_mem);
|
||||
%}
|
||||
|
||||
instruct cmovL_rReg_rReg_memUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, memory src2)
|
||||
instruct cmovL_rReg_rReg_memUCFE_ndd(rRegL dst, cmpOpUCFE cop, rFlagsRegUCFE cr, rRegL src1, memory src2)
|
||||
%{
|
||||
predicate(UseAPX);
|
||||
match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2))));
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %}
|
||||
format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, unsigned, long ndd" %}
|
||||
ins_encode %{
|
||||
__ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address);
|
||||
%}
|
||||
@ -9802,12 +9781,31 @@ instruct cmovF_regU(cmpOpU cop, rFlagsRegU cr, regF dst, regF src)
|
||||
|
||||
instruct cmovF_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regF dst, regF src) %{
|
||||
match(Set dst (CMoveF (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovF_regU(cop, cr, dst, src);
|
||||
%}
|
||||
%}
|
||||
|
||||
instruct cmovF_regUCFE(cmpOpUCFE cop, rFlagsRegUCFE cr, regF dst, regF src)
|
||||
%{
|
||||
match(Set dst (CMoveF (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
format %{ "jn$cop skip\t# signed, unsigned cmove float\n\t"
|
||||
"movss $dst, $src\n"
|
||||
"skip:" %}
|
||||
ins_encode %{
|
||||
Label Lskip;
|
||||
// Invert sense of branch from sense of CMOV
|
||||
__ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip);
|
||||
__ movflt($dst$$XMMRegister, $src$$XMMRegister);
|
||||
__ bind(Lskip);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmovD_reg(cmpOp cop, rFlagsReg cr, regD dst, regD src)
|
||||
%{
|
||||
match(Set dst (CMoveD (Binary cop cr) (Binary dst src)));
|
||||
@ -9846,12 +9844,31 @@ instruct cmovD_regU(cmpOpU cop, rFlagsRegU cr, regD dst, regD src)
|
||||
|
||||
instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{
|
||||
match(Set dst (CMoveD (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200);
|
||||
expand %{
|
||||
cmovD_regU(cop, cr, dst, src);
|
||||
%}
|
||||
%}
|
||||
|
||||
instruct cmovD_regUCFE(cmpOpUCFE cop, rFlagsRegUCFE cr, regD dst, regD src)
|
||||
%{
|
||||
match(Set dst (CMoveD (Binary cop cr) (Binary dst src)));
|
||||
|
||||
ins_cost(200); // XXX
|
||||
format %{ "jn$cop skip\t# signed, unsigned cmove double\n\t"
|
||||
"movsd $dst, $src\n"
|
||||
"skip:" %}
|
||||
ins_encode %{
|
||||
Label Lskip;
|
||||
// Invert sense of branch from sense of CMOV
|
||||
__ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip);
|
||||
__ movdbl($dst$$XMMRegister, $src$$XMMRegister);
|
||||
__ bind(Lskip);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
//----------Arithmetic Instructions--------------------------------------------
|
||||
//----------Addition Instructions----------------------------------------------
|
||||
|
||||
@ -14319,7 +14336,7 @@ instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{
|
||||
instruct cmpF_cc_regCF(rFlagsRegUCF cr, regF src1, regF src2) %{
|
||||
match(Set cr (CmpF src1 src2));
|
||||
|
||||
ins_cost(100);
|
||||
@ -14330,6 +14347,17 @@ instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_regCFE(rFlagsRegUCFE cr, regF src1, regF src2) %{
|
||||
match(Set cr (CmpF src1 src2));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxss $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ vucomxss($src1$$XMMRegister, $src2$$XMMRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
||||
match(Set cr (CmpF src1 (LoadF src2)));
|
||||
|
||||
@ -14341,8 +14369,20 @@ instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_memCFE(rFlagsRegUCFE cr, regF src1, memory src2) %{
|
||||
match(Set cr (CmpF src1 (LoadF src2)));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxss $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ vucomxss($src1$$XMMRegister, $src2$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
||||
match(Set cr (CmpF src con));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
@ -14351,6 +14391,17 @@ instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_immCFE(rFlagsRegUCFE cr, regF src, immF con) %{
|
||||
match(Set cr (CmpF src con));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxss $src, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ vucomxss($src$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// Really expensive, avoid
|
||||
instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2)
|
||||
%{
|
||||
@ -14370,7 +14421,7 @@ instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{
|
||||
instruct cmpD_cc_regCF(rFlagsRegUCF cr, regD src1, regD src2) %{
|
||||
match(Set cr (CmpD src1 src2));
|
||||
|
||||
ins_cost(100);
|
||||
@ -14381,6 +14432,17 @@ instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_regCFE(rFlagsRegUCFE cr, regD src1, regD src2) %{
|
||||
match(Set cr (CmpD src1 src2));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxsd $src1, $src2 test" %}
|
||||
ins_encode %{
|
||||
__ vucomxsd($src1$$XMMRegister, $src2$$XMMRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
||||
match(Set cr (CmpD src1 (LoadD src2)));
|
||||
|
||||
@ -14392,6 +14454,17 @@ instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_memCFE(rFlagsRegUCFE cr, regD src1, memory src2) %{
|
||||
match(Set cr (CmpD src1 (LoadD src2)));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxsd $src1, $src2" %}
|
||||
ins_encode %{
|
||||
__ vucomxsd($src1$$XMMRegister, $src2$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{
|
||||
match(Set cr (CmpD src con));
|
||||
ins_cost(100);
|
||||
@ -14402,6 +14475,17 @@ instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_immCFE(rFlagsRegUCFE cr, regD src, immD con) %{
|
||||
match(Set cr (CmpD src con));
|
||||
|
||||
ins_cost(100);
|
||||
format %{ "vucomxsd $src, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ vucomxsd($src$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// Compare into -1,0,1
|
||||
instruct cmpF_reg(rRegI dst, regF src1, regF src2, rFlagsReg cr)
|
||||
%{
|
||||
@ -16808,6 +16892,21 @@ instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
|
||||
ins_pipe(pipe_jcc);
|
||||
%}
|
||||
|
||||
// Jump Direct Conditional - using signed and unsigned comparison
|
||||
instruct jmpConUCFE(cmpOpUCFE cop, rFlagsRegUCFE cmp, label labl) %{
|
||||
match(If cop cmp);
|
||||
effect(USE labl);
|
||||
|
||||
ins_cost(200);
|
||||
format %{ "j$cop,su $labl" %}
|
||||
size(6);
|
||||
ins_encode %{
|
||||
Label* L = $labl$$label;
|
||||
__ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump
|
||||
%}
|
||||
ins_pipe(pipe_jcc);
|
||||
%}
|
||||
|
||||
// ============================================================================
|
||||
// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary
|
||||
// superklass array for an instance of the superklass. Set a hidden
|
||||
@ -17026,6 +17125,22 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
|
||||
ins_short_branch(1);
|
||||
%}
|
||||
|
||||
// Jump Direct Conditional - using signed and unsigned comparison
|
||||
instruct jmpConUCFE_short(cmpOpUCFE cop, rFlagsRegUCFE cmp, label labl) %{
|
||||
match(If cop cmp);
|
||||
effect(USE labl);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "j$cop,sus $labl" %}
|
||||
size(2);
|
||||
ins_encode %{
|
||||
Label* L = $labl$$label;
|
||||
__ jccb((Assembler::Condition)($cop$$cmpcode), *L);
|
||||
%}
|
||||
ins_pipe(pipe_jcc);
|
||||
ins_short_branch(1);
|
||||
%}
|
||||
|
||||
// ============================================================================
|
||||
// inlined locking and unlocking
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -39,7 +39,7 @@ define_pd_global(bool, UncommonNullCast, true);
|
||||
define_pd_global(bool, DelayCompilerStubsGeneration, false); // Don't have compiler's stubs
|
||||
|
||||
define_pd_global(size_t, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment.
|
||||
define_pd_global(intx, CodeEntryAlignment, 32);
|
||||
define_pd_global(uint, CodeEntryAlignment, 32);
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -38,7 +38,7 @@ class AIXDecoder: public AbstractDecoder {
|
||||
virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } // use AixSymbols::get_function_name to demangle
|
||||
|
||||
virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) {
|
||||
return AixSymbols::get_function_name(addr, buf, buflen, offset, 0, demangle);
|
||||
return AixSymbols::get_function_name(addr, buf, buflen, offset, nullptr, demangle);
|
||||
}
|
||||
virtual bool decode(address addr, char *buf, int buflen, int* offset, const void *base) {
|
||||
ShouldNotReachHere();
|
||||
|
||||
@ -703,7 +703,7 @@ static void *thread_native_entry(Thread *thread) {
|
||||
log_info(os, thread)("Thread finished (tid: %zu, kernel thread id: %zu).",
|
||||
os::current_thread_id(), (uintx) kernel_thread_id);
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool os::create_thread(Thread* thread, ThreadType thr_type,
|
||||
@ -1753,10 +1753,9 @@ bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
void os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
// Do not call this; no need to commit stack pages on AIX.
|
||||
ShouldNotReachHere();
|
||||
return true;
|
||||
}
|
||||
|
||||
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2024 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, 2026, 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
|
||||
@ -78,7 +78,7 @@ class fixed_strings {
|
||||
|
||||
public:
|
||||
|
||||
fixed_strings() : first(0) {}
|
||||
fixed_strings() : first(nullptr) {}
|
||||
~fixed_strings() {
|
||||
node* n = first;
|
||||
while (n) {
|
||||
@ -113,7 +113,7 @@ bool AixSymbols::get_function_name (
|
||||
// information (null if not available)
|
||||
bool demangle // [in] whether to demangle the name
|
||||
) {
|
||||
struct tbtable* tb = 0;
|
||||
struct tbtable* tb = nullptr;
|
||||
unsigned int searchcount = 0;
|
||||
|
||||
// initialize output parameters
|
||||
@ -653,10 +653,10 @@ void AixNativeCallstack::print_callstack_for_context(outputStream* st, const uco
|
||||
|
||||
// To print the first frame, use the current value of iar:
|
||||
// current entry indicated by iar (the current pc)
|
||||
codeptr_t cur_iar = 0;
|
||||
stackptr_t cur_sp = 0;
|
||||
codeptr_t cur_rtoc = 0;
|
||||
codeptr_t cur_lr = 0;
|
||||
codeptr_t cur_iar = nullptr;
|
||||
stackptr_t cur_sp = nullptr;
|
||||
codeptr_t cur_rtoc = nullptr;
|
||||
codeptr_t cur_lr = nullptr;
|
||||
|
||||
const ucontext_t* uc = (const ucontext_t*) context;
|
||||
|
||||
@ -926,7 +926,7 @@ static struct handletableentry* p_handletable = nullptr;
|
||||
static const char* rtv_linkedin_libpath() {
|
||||
constexpr int bufsize = 4096;
|
||||
static char buffer[bufsize];
|
||||
static const char* libpath = 0;
|
||||
static const char* libpath = nullptr;
|
||||
|
||||
// we only try to retrieve the libpath once. After that try we
|
||||
// let libpath point to buffer, which then contains a valid libpath
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
//
|
||||
// Declare Bsd specific flags. They are not available on other platforms.
|
||||
//
|
||||
#ifdef AARCH64
|
||||
#define RUNTIME_OS_FLAGS(develop, \
|
||||
develop_pd, \
|
||||
product, \
|
||||
@ -35,9 +36,21 @@
|
||||
range, \
|
||||
constraint) \
|
||||
\
|
||||
AARCH64_ONLY(develop(bool, AssertWXAtThreadSync, true, \
|
||||
"Conservatively check W^X thread state at possible safepoint" \
|
||||
"or handshake"))
|
||||
develop(bool, TraceWXHealing, false, \
|
||||
"track occurrences of W^X mode healing") \
|
||||
develop(bool, UseOldWX, false, \
|
||||
"Choose old W^X implementation.") \
|
||||
product(bool, StressWXHealing, false, DIAGNOSTIC, \
|
||||
"Stress W xor X healing on MacOS")
|
||||
|
||||
#else
|
||||
#define RUNTIME_OS_FLAGS(develop, \
|
||||
develop_pd, \
|
||||
product, \
|
||||
product_pd, \
|
||||
range, \
|
||||
constraint)
|
||||
#endif
|
||||
|
||||
// end of RUNTIME_OS_FLAGS
|
||||
|
||||
|
||||
@ -841,6 +841,7 @@ jlong os::javaTimeNanos() {
|
||||
// We might also condition (c) on the magnitude of the delta between obsv and now.
|
||||
// Avoiding excessive CAS operations to hot RW locations is critical.
|
||||
// See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
|
||||
// https://web.archive.org/web/20131214182431/https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
|
||||
return (prev == obsv) ? now : obsv;
|
||||
}
|
||||
|
||||
@ -1781,10 +1782,8 @@ bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
|
||||
return os::commit_memory(addr, size, !ExecMem);
|
||||
}
|
||||
|
||||
// If this is a growable mapping, remove the guard pages entirely by
|
||||
// munmap()ping them. If not, just call uncommit_memory().
|
||||
bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
return os::uncommit_memory(addr, size);
|
||||
void os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
os::uncommit_memory(addr, size);
|
||||
}
|
||||
|
||||
// 'requested_addr' is only treated as a hint, the return value may or
|
||||
|
||||
@ -3523,6 +3523,9 @@ bool os::pd_uncommit_memory(char* addr, size_t size, bool exec) {
|
||||
log_trace(os, map)("mmap failed: " RANGEFMT " errno=(%s)",
|
||||
RANGEFMTARGS(addr, size),
|
||||
os::strerror(ep.saved_errno()));
|
||||
if (ep.saved_errno() == ENOMEM) {
|
||||
fatal("Failed to uncommit " RANGEFMT ". It is possible that the process's maximum number of mappings would have been exceeded. Try increasing the limit.", RANGEFMTARGS(addr, size));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -3633,14 +3636,16 @@ bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
|
||||
// It's safe to always unmap guard pages for primordial thread because we
|
||||
// always place it right after end of the mapped region.
|
||||
|
||||
bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
uintptr_t stack_extent, stack_base;
|
||||
void os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
|
||||
if (os::is_primordial_thread()) {
|
||||
return ::munmap(addr, size) == 0;
|
||||
if (::munmap(addr, size) != 0) {
|
||||
fatal("Failed to munmap " RANGEFMT, RANGEFMTARGS(addr, size));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return os::uncommit_memory(addr, size);
|
||||
os::uncommit_memory(addr, size);
|
||||
}
|
||||
|
||||
// 'requested_addr' is only treated as a hint, the return value may or
|
||||
|
||||
@ -3281,11 +3281,10 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
|
||||
// Do manual alignment
|
||||
aligned_base = align_up(extra_base, alignment);
|
||||
|
||||
bool rc = (file_desc != -1) ? os::unmap_memory(extra_base, extra_size) :
|
||||
os::release_memory(extra_base, extra_size);
|
||||
assert(rc, "release failed");
|
||||
if (!rc) {
|
||||
return nullptr;
|
||||
if (file_desc != -1) {
|
||||
os::unmap_memory(extra_base, extra_size);
|
||||
} else {
|
||||
os::release_memory(extra_base, extra_size);
|
||||
}
|
||||
|
||||
// Attempt to map, into the just vacated space, the slightly smaller aligned area.
|
||||
@ -3681,8 +3680,8 @@ bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
|
||||
return os::commit_memory(addr, size, !ExecMem);
|
||||
}
|
||||
|
||||
bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
return os::uncommit_memory(addr, size);
|
||||
void os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
os::uncommit_memory(addr, size);
|
||||
}
|
||||
|
||||
static bool protect_pages_individually(char* addr, size_t bytes, unsigned int p, DWORD *old_status) {
|
||||
|
||||
@ -54,8 +54,11 @@
|
||||
#include "signals_posix.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/decoder.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/nativeStackPrinter.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
|
||||
// put OS-includes here
|
||||
# include <sys/types.h>
|
||||
@ -85,6 +88,8 @@
|
||||
#define SPELL_REG_SP "sp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
WXMode DefaultWXWriteMode;
|
||||
|
||||
// see darwin-xnu/osfmk/mach/arm/_structs.h
|
||||
|
||||
// 10.5 UNIX03 member name prefixes
|
||||
@ -233,19 +238,56 @@ NOINLINE frame os::current_frame() {
|
||||
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
// Enable WXWrite: this function is called by the signal handler at arbitrary
|
||||
// point of execution.
|
||||
ThreadWXEnable wx(WXWrite, thread);
|
||||
|
||||
// decide if this trap can be handled by a stub
|
||||
address stub = nullptr;
|
||||
|
||||
address pc = nullptr;
|
||||
address pc = nullptr;
|
||||
|
||||
//%note os_trap_1
|
||||
if (info != nullptr && uc != nullptr && thread != nullptr) {
|
||||
pc = (address) os::Posix::ucontext_get_pc(uc);
|
||||
|
||||
#ifdef MACOS_AARCH64
|
||||
// If we got a SIGBUS because we tried to write into the code
|
||||
// cache, try enabling WXWrite mode.
|
||||
if (sig == SIGBUS
|
||||
&& pc != info->si_addr
|
||||
&& CodeCache::contains(info->si_addr)
|
||||
&& os::address_is_in_vm(pc)) {
|
||||
WXMode *entry_mode = thread->_cur_wx_mode;
|
||||
if (entry_mode != nullptr && *entry_mode == WXArmedForWrite) {
|
||||
if (TraceWXHealing) {
|
||||
static const char *mode_names[3] = {"WXWrite", "WXExec", "WXArmedForWrite"};
|
||||
tty->print("Healing WXMode %s at %p to WXWrite",
|
||||
mode_names[*entry_mode], entry_mode);
|
||||
char name[128];
|
||||
int offset = 0;
|
||||
if (os::dll_address_to_function_name(pc, name, sizeof name, &offset)) {
|
||||
tty->print_cr(" (%s+0x%x)", name, offset);
|
||||
} else {
|
||||
tty->cr();
|
||||
}
|
||||
if (Verbose) {
|
||||
char buf[O_BUFLEN];
|
||||
NativeStackPrinter nsp(thread);
|
||||
nsp.print_stack(tty, buf, sizeof(buf), pc,
|
||||
true /* print_source_info */, -1 /* max stack */);
|
||||
}
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
guarantee(StressWXHealing,
|
||||
"We should not reach here unless StressWXHealing");
|
||||
#endif
|
||||
*(thread->_cur_wx_mode) = WXWrite;
|
||||
return thread->wx_enable_write();
|
||||
}
|
||||
}
|
||||
|
||||
// There may be cases where code after this point that we call
|
||||
// from the signal handler changes WX state, so we protect against
|
||||
// that by saving and restoring the state.
|
||||
ThreadWXEnable wx(thread->get_wx_state(), thread);
|
||||
#endif
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
address addr = (address) info->si_addr;
|
||||
@ -515,11 +557,42 @@ int os::extra_bang_size_in_bytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef MACOS_AARCH64
|
||||
THREAD_LOCAL bool os::_jit_exec_enabled;
|
||||
|
||||
// This is a wrapper around the standard library function
|
||||
// pthread_jit_write_protect_np(3). We keep track of the state of
|
||||
// per-thread write protection on the MAP_JIT region in the
|
||||
// thread-local variable os::_jit_exec_enabled
|
||||
void os::current_thread_enable_wx(WXMode mode) {
|
||||
pthread_jit_write_protect_np(mode == WXExec);
|
||||
bool exec_enabled = mode != WXWrite;
|
||||
if (exec_enabled != _jit_exec_enabled NOT_PRODUCT( || DefaultWXWriteMode == WXWrite)) {
|
||||
permit_forbidden_function::pthread_jit_write_protect_np(exec_enabled);
|
||||
_jit_exec_enabled = exec_enabled;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If the current thread is in the WX state WXArmedForWrite, change
|
||||
// the state to WXWrite.
|
||||
bool Thread::wx_enable_write() {
|
||||
if (_wx_state == WXArmedForWrite) {
|
||||
_wx_state = WXWrite;
|
||||
os::current_thread_enable_wx(WXWrite);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper around wx_enable_write() for when the current thread is
|
||||
// not known.
|
||||
void os::thread_wx_enable_write_impl() {
|
||||
if (!StressWXHealing) {
|
||||
Thread::current()->wx_enable_write();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MACOS_AARCH64
|
||||
|
||||
static inline void atomic_copy64(const volatile void *src, volatile void *dst) {
|
||||
*(jlong *) dst = *(const jlong *) src;
|
||||
|
||||
@ -42,6 +42,16 @@ frame JavaThread::pd_last_frame() {
|
||||
void JavaThread::cache_global_variables() {
|
||||
BarrierSet* bs = BarrierSet::barrier_set();
|
||||
|
||||
#if INCLUDE_G1GC
|
||||
if (bs->is_a(BarrierSet::G1BarrierSet)) {
|
||||
_card_table_base = nullptr;
|
||||
} else
|
||||
#endif
|
||||
#if INCLUDE_SHENANDOAHGC
|
||||
if (bs->is_a(BarrierSet::ShenandoahBarrierSet)) {
|
||||
_card_table_base = nullptr;
|
||||
} else
|
||||
#endif
|
||||
if (bs->is_a(BarrierSet::CardTableBarrierSet)) {
|
||||
CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set();
|
||||
_card_table_base = (address)ctbs->card_table_base_const();
|
||||
|
||||
@ -136,9 +136,9 @@ void *AdlArena::Acalloc( size_t items, size_t x ) {
|
||||
}
|
||||
|
||||
//------------------------------realloc----------------------------------------
|
||||
static size_t pointer_delta(const void *left, const void *right) {
|
||||
assert(left >= right, "pointer delta underflow");
|
||||
return (uintptr_t)left - (uintptr_t)right;
|
||||
static size_t pointer_delta(const void* high, const void* low) {
|
||||
assert(high >= low, "pointer delta underflow");
|
||||
return (uintptr_t)high - (uintptr_t)low;
|
||||
}
|
||||
|
||||
// Reallocate storage in AdlArena.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, 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
|
||||
@ -98,6 +98,8 @@ CodeBuffer::CodeBuffer(const CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(
|
||||
}
|
||||
|
||||
void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
|
||||
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
|
||||
|
||||
// Always allow for empty slop around each section.
|
||||
int slop = (int) CodeSection::end_slop();
|
||||
|
||||
@ -466,9 +468,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
|
||||
assert(!_finalize_stubs, "non-finalized stubs");
|
||||
|
||||
{
|
||||
// not sure why this is here, but why not...
|
||||
int alignSize = MAX2((intx) sizeof(jdouble), CodeEntryAlignment);
|
||||
assert( (dest->_total_start - _insts.start()) % alignSize == 0, "copy must preserve alignment");
|
||||
assert( (dest->_total_start - _insts.start()) % CodeEntryAlignment == 0, "copy must preserve alignment");
|
||||
}
|
||||
|
||||
const CodeSection* prev_cs = nullptr;
|
||||
|
||||
@ -541,6 +541,7 @@ extern void vm_exit(int code);
|
||||
// unpack_with_exception entry instead. This makes life for the exception blob easier
|
||||
// because making that same check and diverting is painful from assembly language.
|
||||
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm))
|
||||
MACOS_AARCH64_ONLY(current->wx_enable_write());
|
||||
Handle exception(current, ex);
|
||||
|
||||
// This function is called when we are about to throw an exception. Therefore,
|
||||
|
||||
30
src/hotspot/share/cds/aotCompressedPointers.cpp
Normal file
30
src/hotspot/share/cds/aotCompressedPointers.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
|
||||
size_t AOTCompressedPointers::compute_byte_offset(address p) {
|
||||
return ArchiveBuilder::current()->any_to_offset(p);
|
||||
}
|
||||
142
src/hotspot/share/cds/aotCompressedPointers.hpp
Normal file
142
src/hotspot/share/cds/aotCompressedPointers.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 SHARE_CDS_AOTCOMPRESSEDPOINTERS_HPP
|
||||
#define SHARE_CDS_AOTCOMPRESSEDPOINTERS_HPP
|
||||
|
||||
#include "cds/cds_globals.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "memory/metaspace.hpp"
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class AOTCompressedPointers: public AllStatic {
|
||||
public:
|
||||
// For space saving, we can encode the location of metadata objects in the "rw" and "ro"
|
||||
// regions using a 32-bit offset from the bottom of the mapped AOT metaspace.
|
||||
// Currently we allow only up to 2GB total size in the rw and ro regions (which are
|
||||
// contiguous to each other).
|
||||
enum class narrowPtr : u4;
|
||||
static constexpr size_t MaxMetadataOffsetBytes = 0x7FFFFFFF;
|
||||
|
||||
// In the future, this could return a different numerical value than
|
||||
// narrowp if the encoding contains shifts.
|
||||
inline static size_t get_byte_offset(narrowPtr narrowp) {
|
||||
return checked_cast<size_t>(narrowp);
|
||||
}
|
||||
|
||||
inline static narrowPtr null() {
|
||||
return static_cast<narrowPtr>(0);
|
||||
}
|
||||
|
||||
// Encoding ------
|
||||
|
||||
// ptr can point to one of the following
|
||||
// - an object in the ArchiveBuilder's buffer.
|
||||
// - an object in the currently mapped AOT cache rw/ro regions.
|
||||
// - an object that has been copied into the ArchiveBuilder's buffer.
|
||||
template <typename T>
|
||||
static narrowPtr encode_not_null(T ptr) {
|
||||
address p = reinterpret_cast<address>(ptr);
|
||||
return encode_byte_offset(compute_byte_offset(p));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static narrowPtr encode(T ptr) { // may be null
|
||||
if (ptr == nullptr) {
|
||||
return null();
|
||||
} else {
|
||||
return encode_not_null(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// ptr must be in the currently mapped AOT cache rw/ro regions.
|
||||
template <typename T>
|
||||
static narrowPtr encode_address_in_cache(T ptr) {
|
||||
assert(Metaspace::in_aot_cache(ptr), "must be");
|
||||
address p = reinterpret_cast<address>(ptr);
|
||||
address base = reinterpret_cast<address>(SharedBaseAddress);
|
||||
return encode_byte_offset(pointer_delta(p, base, 1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static narrowPtr encode_address_in_cache_or_null(T ptr) {
|
||||
if (ptr == nullptr) {
|
||||
return null();
|
||||
} else {
|
||||
return encode_address_in_cache<T>(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Decoding -----
|
||||
|
||||
// If base_address is null, decode an address within the mapped aot cache range.
|
||||
template <typename T>
|
||||
static T decode_not_null(narrowPtr narrowp, address base_address = nullptr) {
|
||||
assert(narrowp != null(), "sanity");
|
||||
if (base_address == nullptr) {
|
||||
T p = reinterpret_cast<T>(reinterpret_cast<address>(SharedBaseAddress) + get_byte_offset(narrowp));
|
||||
assert(Metaspace::in_aot_cache(p), "must be");
|
||||
return p;
|
||||
} else {
|
||||
// This is usually called before the cache is fully mapped.
|
||||
return reinterpret_cast<T>(base_address + get_byte_offset(narrowp));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T decode(narrowPtr narrowp, address base_address = nullptr) { // may be null
|
||||
if (narrowp == null()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return decode_not_null<T>(narrowp, base_address);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t compute_byte_offset(address p);
|
||||
|
||||
static narrowPtr encode_byte_offset(size_t offset) {
|
||||
assert(offset != 0, "offset 0 is in protection zone");
|
||||
precond(offset <= MaxMetadataOffsetBytes);
|
||||
return checked_cast<narrowPtr>(offset);
|
||||
}
|
||||
};
|
||||
|
||||
// Type casts -- declared as global functions to save a few keystrokes
|
||||
|
||||
// A simple type cast. No change in numerical value.
|
||||
inline AOTCompressedPointers::narrowPtr cast_from_u4(u4 narrowp) {
|
||||
return checked_cast<AOTCompressedPointers::narrowPtr>(narrowp);
|
||||
}
|
||||
|
||||
// A simple type cast. No change in numerical value.
|
||||
// !!!DO NOT CALL THIS if you want a byte offset!!!
|
||||
inline u4 cast_to_u4(AOTCompressedPointers::narrowPtr narrowp) {
|
||||
return checked_cast<u4>(narrowp);
|
||||
}
|
||||
|
||||
#endif // SHARE_CDS_AOTCOMPRESSEDPOINTERS_HPP
|
||||
@ -88,7 +88,7 @@ void AOTMapLogger::ergo_initialize() {
|
||||
}
|
||||
|
||||
void AOTMapLogger::dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info, ArchiveStreamedHeapInfo* streamed_heap_info,
|
||||
AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info,
|
||||
char* bitmap, size_t bitmap_size_in_bytes) {
|
||||
_is_runtime_logging = false;
|
||||
_buffer_to_requested_delta = ArchiveBuilder::current()->buffer_to_requested_delta();
|
||||
@ -823,7 +823,7 @@ public:
|
||||
}
|
||||
}; // AOTMapLogger::ArchivedFieldPrinter
|
||||
|
||||
void AOTMapLogger::dumptime_log_mapped_heap_region(ArchiveMappedHeapInfo* heap_info) {
|
||||
void AOTMapLogger::dumptime_log_mapped_heap_region(AOTMappedHeapInfo* heap_info) {
|
||||
MemRegion r = heap_info->buffer_region();
|
||||
address buffer_start = address(r.start()); // start of the current oop inside the buffer
|
||||
address buffer_end = address(r.end());
|
||||
@ -835,7 +835,7 @@ void AOTMapLogger::dumptime_log_mapped_heap_region(ArchiveMappedHeapInfo* heap_i
|
||||
log_archived_objects(AOTMappedHeapWriter::oop_iterator(heap_info));
|
||||
}
|
||||
|
||||
void AOTMapLogger::dumptime_log_streamed_heap_region(ArchiveStreamedHeapInfo* heap_info) {
|
||||
void AOTMapLogger::dumptime_log_streamed_heap_region(AOTStreamedHeapInfo* heap_info) {
|
||||
MemRegion r = heap_info->buffer_region();
|
||||
address buffer_start = address(r.start()); // start of the current oop inside the buffer
|
||||
address buffer_end = address(r.end());
|
||||
|
||||
@ -33,8 +33,8 @@
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
class ArchiveMappedHeapInfo;
|
||||
class ArchiveStreamedHeapInfo;
|
||||
class AOTMappedHeapInfo;
|
||||
class AOTStreamedHeapInfo;
|
||||
class CompileTrainingData;
|
||||
class DumpRegion;
|
||||
class FileMapInfo;
|
||||
@ -157,8 +157,8 @@ private:
|
||||
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
static void dumptime_log_mapped_heap_region(ArchiveMappedHeapInfo* mapped_heap_info);
|
||||
static void dumptime_log_streamed_heap_region(ArchiveStreamedHeapInfo* streamed_heap_info);
|
||||
static void dumptime_log_mapped_heap_region(AOTMappedHeapInfo* mapped_heap_info);
|
||||
static void dumptime_log_streamed_heap_region(AOTStreamedHeapInfo* streamed_heap_info);
|
||||
static void runtime_log_heap_region(FileMapInfo* mapinfo);
|
||||
|
||||
static void print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_location = true);
|
||||
@ -173,7 +173,7 @@ public:
|
||||
static bool is_logging_at_bootstrap() { return _is_logging_at_bootstrap; }
|
||||
|
||||
static void dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info, ArchiveStreamedHeapInfo* streamed_heap_info,
|
||||
AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info,
|
||||
char* bitmap, size_t bitmap_size_in_bytes);
|
||||
static void runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo);
|
||||
};
|
||||
|
||||
49
src/hotspot/share/cds/aotMappedHeap.cpp
Normal file
49
src/hotspot/share/cds/aotMappedHeap.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 "cds/aotMappedHeap.hpp"
|
||||
|
||||
// Anything that goes in the header must be thoroughly purged from uninitialized memory
|
||||
// as it will be written to disk. Therefore, the constructors memset the memory to 0.
|
||||
// This is not the prettiest thing, but we need to know every byte is initialized,
|
||||
// including potential padding between fields.
|
||||
|
||||
AOTMappedHeapHeader::AOTMappedHeapHeader(size_t ptrmap_start_pos,
|
||||
size_t oopmap_start_pos,
|
||||
HeapRootSegments root_segments) {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
_ptrmap_start_pos = ptrmap_start_pos;
|
||||
_oopmap_start_pos = oopmap_start_pos;
|
||||
_root_segments = root_segments;
|
||||
}
|
||||
|
||||
AOTMappedHeapHeader::AOTMappedHeapHeader() {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
AOTMappedHeapHeader AOTMappedHeapInfo::create_header() {
|
||||
return AOTMappedHeapHeader{_ptrmap_start_pos,
|
||||
_oopmap_start_pos,
|
||||
_root_segments};
|
||||
}
|
||||
168
src/hotspot/share/cds/aotMappedHeap.hpp
Normal file
168
src/hotspot/share/cds/aotMappedHeap.hpp
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 SHARE_CDS_AOTMAPPEDHEAP_HPP
|
||||
#define SHARE_CDS_AOTMAPPEDHEAP_HPP
|
||||
|
||||
#include "cds/aotMapLogger.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class AOTMappedHeapHeader {
|
||||
size_t _ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
|
||||
size_t _oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
|
||||
HeapRootSegments _root_segments; // Heap root segments info
|
||||
|
||||
public:
|
||||
AOTMappedHeapHeader();
|
||||
AOTMappedHeapHeader(size_t ptrmap_start_pos,
|
||||
size_t oopmap_start_pos,
|
||||
HeapRootSegments root_segments);
|
||||
|
||||
size_t ptrmap_start_pos() const { return _ptrmap_start_pos; }
|
||||
size_t oopmap_start_pos() const { return _oopmap_start_pos; }
|
||||
HeapRootSegments root_segments() const { return _root_segments; }
|
||||
|
||||
// This class is trivially copyable and assignable.
|
||||
AOTMappedHeapHeader(const AOTMappedHeapHeader&) = default;
|
||||
AOTMappedHeapHeader& operator=(const AOTMappedHeapHeader&) = default;
|
||||
};
|
||||
|
||||
class AOTMappedHeapInfo {
|
||||
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
|
||||
CHeapBitMap _oopmap;
|
||||
CHeapBitMap _ptrmap;
|
||||
HeapRootSegments _root_segments;
|
||||
size_t _oopmap_start_pos; // How many zeros were removed from the beginning of the bit map?
|
||||
size_t _ptrmap_start_pos; // How many zeros were removed from the beginning of the bit map?
|
||||
|
||||
public:
|
||||
AOTMappedHeapInfo() :
|
||||
_buffer_region(),
|
||||
_oopmap(128, mtClassShared),
|
||||
_ptrmap(128, mtClassShared),
|
||||
_root_segments(),
|
||||
_oopmap_start_pos(),
|
||||
_ptrmap_start_pos() {}
|
||||
bool is_used() { return !_buffer_region.is_empty(); }
|
||||
|
||||
MemRegion buffer_region() { return _buffer_region; }
|
||||
void set_buffer_region(MemRegion r) { _buffer_region = r; }
|
||||
|
||||
char* buffer_start() { return (char*)_buffer_region.start(); }
|
||||
size_t buffer_byte_size() { return _buffer_region.byte_size(); }
|
||||
|
||||
CHeapBitMap* oopmap() { return &_oopmap; }
|
||||
CHeapBitMap* ptrmap() { return &_ptrmap; }
|
||||
|
||||
void set_oopmap_start_pos(size_t start_pos) { _oopmap_start_pos = start_pos; }
|
||||
void set_ptrmap_start_pos(size_t start_pos) { _ptrmap_start_pos = start_pos; }
|
||||
|
||||
void set_root_segments(HeapRootSegments segments) { _root_segments = segments; };
|
||||
HeapRootSegments root_segments() { return _root_segments; }
|
||||
|
||||
AOTMappedHeapHeader create_header();
|
||||
};
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
class AOTMappedHeapOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
protected:
|
||||
address _current;
|
||||
address _next;
|
||||
|
||||
address _buffer_start;
|
||||
address _buffer_end;
|
||||
uint64_t _buffer_start_narrow_oop;
|
||||
intptr_t _buffer_to_requested_delta;
|
||||
int _requested_shift;
|
||||
|
||||
size_t _num_root_segments;
|
||||
size_t _num_obj_arrays_logged;
|
||||
|
||||
public:
|
||||
AOTMappedHeapOopIterator(address buffer_start,
|
||||
address buffer_end,
|
||||
address requested_base,
|
||||
address requested_start,
|
||||
int requested_shift,
|
||||
size_t num_root_segments)
|
||||
: _current(nullptr),
|
||||
_next(buffer_start),
|
||||
_buffer_start(buffer_start),
|
||||
_buffer_end(buffer_end),
|
||||
_requested_shift(requested_shift),
|
||||
_num_root_segments(num_root_segments),
|
||||
_num_obj_arrays_logged(0) {
|
||||
_buffer_to_requested_delta = requested_start - buffer_start;
|
||||
_buffer_start_narrow_oop = 0xdeadbeed;
|
||||
if (UseCompressedOops) {
|
||||
_buffer_start_narrow_oop = (uint64_t)(pointer_delta(requested_start, requested_base, 1)) >> requested_shift;
|
||||
assert(_buffer_start_narrow_oop < 0xffffffff, "sanity");
|
||||
}
|
||||
}
|
||||
|
||||
virtual AOTMapLogger::OopData capture(address buffered_addr) = 0;
|
||||
|
||||
bool has_next() override {
|
||||
return _next < _buffer_end;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
if (result._klass->is_objArray_klass()) {
|
||||
result._is_root_segment = _num_obj_arrays_logged++ < _num_root_segments;
|
||||
}
|
||||
_next = _current + result._size * BytesPerWord;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
uint64_t n = (uint64_t)(*addr);
|
||||
if (n == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
precond(n >= _buffer_start_narrow_oop);
|
||||
address buffer_addr = _buffer_start + ((n - _buffer_start_narrow_oop) << _requested_shift);
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
address requested_value = cast_from_oop<address>(*addr);
|
||||
if (requested_value == nullptr) {
|
||||
return null_data();
|
||||
} else {
|
||||
address buffer_addr = requested_value - _buffer_to_requested_delta;
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* roots() override {
|
||||
return new GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>();
|
||||
}
|
||||
};
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
#endif // SHARE_CDS_AOTMAPPEDHEAP_HPP
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/aotMappedHeap.hpp"
|
||||
#include "cds/aotMappedHeapLoader.inline.hpp"
|
||||
#include "cds/aotMappedHeapWriter.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
@ -221,7 +222,7 @@ void AOTMappedHeapLoader::patch_embedded_pointers(FileMapInfo* info,
|
||||
// the heap object may be loaded at a different address at run time. This structure is used
|
||||
// to translate the dump time addresses for all objects in FileMapInfo::space_at(region_index)
|
||||
// to their runtime addresses.
|
||||
struct LoadedArchiveHeapRegion {
|
||||
struct AOTMappedHeapRegion {
|
||||
int _region_index; // index for FileMapInfo::space_at(index)
|
||||
size_t _region_size; // number of bytes in this region
|
||||
uintptr_t _dumptime_base; // The dump-time (decoded) address of the first object in this region
|
||||
@ -232,7 +233,7 @@ struct LoadedArchiveHeapRegion {
|
||||
}
|
||||
};
|
||||
|
||||
void AOTMappedHeapLoader::init_loaded_heap_relocation(LoadedArchiveHeapRegion* loaded_region) {
|
||||
void AOTMappedHeapLoader::init_loaded_heap_relocation(AOTMappedHeapRegion* loaded_region) {
|
||||
_dumptime_base = loaded_region->_dumptime_base;
|
||||
_dumptime_top = loaded_region->top();
|
||||
_runtime_offset = loaded_region->_runtime_offset;
|
||||
@ -249,7 +250,7 @@ class AOTMappedHeapLoader::PatchLoadedRegionPointers: public BitMapClosure {
|
||||
uintptr_t _top;
|
||||
|
||||
public:
|
||||
PatchLoadedRegionPointers(narrowOop* start, LoadedArchiveHeapRegion* loaded_region)
|
||||
PatchLoadedRegionPointers(narrowOop* start, AOTMappedHeapRegion* loaded_region)
|
||||
: _start(start),
|
||||
_offset(loaded_region->_runtime_offset),
|
||||
_base(loaded_region->_dumptime_base),
|
||||
@ -270,7 +271,7 @@ class AOTMappedHeapLoader::PatchLoadedRegionPointers: public BitMapClosure {
|
||||
}
|
||||
};
|
||||
|
||||
bool AOTMappedHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region,
|
||||
bool AOTMappedHeapLoader::init_loaded_region(FileMapInfo* mapinfo, AOTMappedHeapRegion* loaded_region,
|
||||
MemRegion& archive_space) {
|
||||
size_t total_bytes = 0;
|
||||
FileMapRegion* r = mapinfo->region_at(AOTMetaspace::hp);
|
||||
@ -301,7 +302,7 @@ bool AOTMappedHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchive
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOTMappedHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region,
|
||||
bool AOTMappedHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, AOTMappedHeapRegion* loaded_region,
|
||||
uintptr_t load_address) {
|
||||
uintptr_t bitmap_base = (uintptr_t)mapinfo->map_bitmap_region();
|
||||
if (bitmap_base == 0) {
|
||||
@ -340,7 +341,7 @@ bool AOTMappedHeapLoader::load_heap_region(FileMapInfo* mapinfo) {
|
||||
assert(can_load(), "loaded heap for must be supported");
|
||||
init_narrow_oop_decoding(mapinfo->narrow_oop_base(), mapinfo->narrow_oop_shift());
|
||||
|
||||
LoadedArchiveHeapRegion loaded_region;
|
||||
AOTMappedHeapRegion loaded_region;
|
||||
memset(&loaded_region, 0, sizeof(loaded_region));
|
||||
|
||||
MemRegion archive_space;
|
||||
@ -733,40 +734,22 @@ void AOTMappedHeapLoader::dealloc_heap_region(FileMapInfo* info) {
|
||||
}
|
||||
|
||||
AOTMapLogger::OopDataIterator* AOTMappedHeapLoader::oop_iterator(FileMapInfo* info, address buffer_start, address buffer_end) {
|
||||
class MappedLoaderOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
private:
|
||||
address _current;
|
||||
address _next;
|
||||
|
||||
address _buffer_start;
|
||||
address _buffer_end;
|
||||
uint64_t _buffer_start_narrow_oop;
|
||||
intptr_t _buffer_to_requested_delta;
|
||||
int _requested_shift;
|
||||
|
||||
size_t _num_root_segments;
|
||||
size_t _num_obj_arrays_logged;
|
||||
|
||||
class MappedLoaderOopIterator : public AOTMappedHeapOopIterator {
|
||||
public:
|
||||
MappedLoaderOopIterator(address buffer_start,
|
||||
address buffer_end,
|
||||
uint64_t buffer_start_narrow_oop,
|
||||
intptr_t buffer_to_requested_delta,
|
||||
address requested_base,
|
||||
address requested_start,
|
||||
int requested_shift,
|
||||
size_t num_root_segments)
|
||||
: _current(nullptr),
|
||||
_next(buffer_start),
|
||||
_buffer_start(buffer_start),
|
||||
_buffer_end(buffer_end),
|
||||
_buffer_start_narrow_oop(buffer_start_narrow_oop),
|
||||
_buffer_to_requested_delta(buffer_to_requested_delta),
|
||||
_requested_shift(requested_shift),
|
||||
_num_root_segments(num_root_segments),
|
||||
_num_obj_arrays_logged(0) {
|
||||
}
|
||||
size_t num_root_segments) :
|
||||
AOTMappedHeapOopIterator(buffer_start,
|
||||
buffer_end,
|
||||
requested_base,
|
||||
requested_start,
|
||||
requested_shift,
|
||||
num_root_segments) {}
|
||||
|
||||
|
||||
AOTMapLogger::OopData capture(address buffered_addr) {
|
||||
AOTMapLogger::OopData capture(address buffered_addr) override {
|
||||
oopDesc* raw_oop = (oopDesc*)buffered_addr;
|
||||
size_t size = raw_oop->size();
|
||||
address requested_addr = buffered_addr + _buffer_to_requested_delta;
|
||||
@ -784,62 +767,17 @@ AOTMapLogger::OopDataIterator* AOTMappedHeapLoader::oop_iterator(FileMapInfo* in
|
||||
size,
|
||||
false };
|
||||
}
|
||||
|
||||
bool has_next() override {
|
||||
return _next < _buffer_end;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
if (result._klass->is_objArray_klass()) {
|
||||
result._is_root_segment = _num_obj_arrays_logged++ < _num_root_segments;
|
||||
}
|
||||
_next = _current + result._size * BytesPerWord;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
uint64_t n = (uint64_t)(*addr);
|
||||
if (n == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
precond(n >= _buffer_start_narrow_oop);
|
||||
address buffer_addr = _buffer_start + ((n - _buffer_start_narrow_oop) << _requested_shift);
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
address requested_value = cast_from_oop<address>(*addr);
|
||||
if (requested_value == nullptr) {
|
||||
return null_data();
|
||||
} else {
|
||||
address buffer_addr = requested_value - _buffer_to_requested_delta;
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* roots() override {
|
||||
return new GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>();
|
||||
}
|
||||
};
|
||||
|
||||
FileMapRegion* r = info->region_at(AOTMetaspace::hp);
|
||||
address requested_base = UseCompressedOops ? (address)info->narrow_oop_base() : heap_region_requested_address(info);
|
||||
address requested_start = requested_base + r->mapping_offset();
|
||||
int requested_shift = info->narrow_oop_shift();
|
||||
intptr_t buffer_to_requested_delta = requested_start - buffer_start;
|
||||
uint64_t buffer_start_narrow_oop = 0xdeadbeed;
|
||||
if (UseCompressedOops) {
|
||||
buffer_start_narrow_oop = (uint64_t)(pointer_delta(requested_start, requested_base, 1)) >> requested_shift;
|
||||
assert(buffer_start_narrow_oop < 0xffffffff, "sanity");
|
||||
}
|
||||
|
||||
return new MappedLoaderOopIterator(buffer_start,
|
||||
buffer_end,
|
||||
buffer_start_narrow_oop,
|
||||
buffer_to_requested_delta,
|
||||
requested_base,
|
||||
requested_start,
|
||||
requested_shift,
|
||||
info->mapped_heap()->root_segments().count());
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, 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
|
||||
@ -37,8 +37,8 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
struct AOTMappedHeapRegion;
|
||||
class FileMapInfo;
|
||||
struct LoadedArchiveHeapRegion;
|
||||
|
||||
class AOTMappedHeapLoader : AllStatic {
|
||||
friend class AOTMapLogger;
|
||||
@ -93,7 +93,7 @@ public:
|
||||
// function instead.
|
||||
inline static oop decode_from_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
|
||||
|
||||
// More efficient version, but works only when ArchiveHeap is mapped.
|
||||
// More efficient version, but works only when is_mapped()
|
||||
inline static oop decode_from_mapped_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
|
||||
|
||||
static void patch_compressed_embedded_pointers(BitMapView bm,
|
||||
@ -113,7 +113,7 @@ private:
|
||||
static bool _is_loaded;
|
||||
|
||||
// Support for loaded archived heap. These are cached values from
|
||||
// LoadedArchiveHeapRegion's.
|
||||
// AOTMappedHeapRegion's.
|
||||
static uintptr_t _dumptime_base;
|
||||
static uintptr_t _dumptime_top;
|
||||
static intx _runtime_offset;
|
||||
@ -141,10 +141,10 @@ private:
|
||||
static bool _heap_pointers_need_patching;
|
||||
|
||||
static void init_narrow_oop_decoding(address base, int shift);
|
||||
static bool init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region,
|
||||
static bool init_loaded_region(FileMapInfo* mapinfo, AOTMappedHeapRegion* loaded_region,
|
||||
MemRegion& archive_space);
|
||||
static bool load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region, uintptr_t buffer);
|
||||
static void init_loaded_heap_relocation(LoadedArchiveHeapRegion* reloc_info);
|
||||
static bool load_heap_region_impl(FileMapInfo* mapinfo, AOTMappedHeapRegion* loaded_region, uintptr_t buffer);
|
||||
static void init_loaded_heap_relocation(AOTMappedHeapRegion* reloc_info);
|
||||
static void patch_native_pointers();
|
||||
static void finish_loaded_heap();
|
||||
static void verify_loaded_heap();
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotMappedHeapLoader.hpp"
|
||||
#include "cds/aotMappedHeap.hpp"
|
||||
#include "cds/aotMappedHeapWriter.hpp"
|
||||
#include "cds/aotReferenceObjSupport.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
@ -151,7 +151,7 @@ void AOTMappedHeapWriter::add_source_obj(oop src_obj) {
|
||||
}
|
||||
|
||||
void AOTMappedHeapWriter::write(GrowableArrayCHeap<oop, mtClassShared>* roots,
|
||||
ArchiveMappedHeapInfo* heap_info) {
|
||||
AOTMappedHeapInfo* heap_info) {
|
||||
assert(CDSConfig::is_dumping_heap(), "sanity");
|
||||
allocate_buffer();
|
||||
copy_source_objs_to_buffer(roots);
|
||||
@ -598,7 +598,7 @@ size_t AOTMappedHeapWriter::copy_one_source_obj_to_buffer(oop src_obj) {
|
||||
//
|
||||
// So we just hard code it to NOCOOPS_REQUESTED_BASE.
|
||||
//
|
||||
void AOTMappedHeapWriter::set_requested_address_range(ArchiveMappedHeapInfo* info) {
|
||||
void AOTMappedHeapWriter::set_requested_address_range(AOTMappedHeapInfo* info) {
|
||||
assert(!info->is_used(), "only set once");
|
||||
|
||||
size_t heap_region_byte_size = _buffer_used;
|
||||
@ -792,7 +792,7 @@ static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bit
|
||||
|
||||
// Update all oop fields embedded in the buffered objects
|
||||
void AOTMappedHeapWriter::relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots,
|
||||
ArchiveMappedHeapInfo* heap_info) {
|
||||
AOTMappedHeapInfo* heap_info) {
|
||||
size_t oopmap_unit = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
|
||||
size_t heap_region_byte_size = _buffer_used;
|
||||
heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit);
|
||||
@ -862,7 +862,7 @@ void AOTMappedHeapWriter::mark_native_pointers(oop orig_obj) {
|
||||
});
|
||||
}
|
||||
|
||||
void AOTMappedHeapWriter::compute_ptrmap(ArchiveMappedHeapInfo* heap_info) {
|
||||
void AOTMappedHeapWriter::compute_ptrmap(AOTMappedHeapInfo* heap_info) {
|
||||
int num_non_null_ptrs = 0;
|
||||
Metadata** bottom = (Metadata**) _requested_bottom;
|
||||
Metadata** top = (Metadata**) _requested_top; // exclusive
|
||||
@ -909,40 +909,23 @@ void AOTMappedHeapWriter::compute_ptrmap(ArchiveMappedHeapInfo* heap_info) {
|
||||
num_non_null_ptrs, size_t(heap_info->ptrmap()->size()));
|
||||
}
|
||||
|
||||
AOTMapLogger::OopDataIterator* AOTMappedHeapWriter::oop_iterator(ArchiveMappedHeapInfo* heap_info) {
|
||||
class MappedWriterOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
private:
|
||||
address _current;
|
||||
address _next;
|
||||
|
||||
address _buffer_start;
|
||||
address _buffer_end;
|
||||
uint64_t _buffer_start_narrow_oop;
|
||||
intptr_t _buffer_to_requested_delta;
|
||||
int _requested_shift;
|
||||
|
||||
size_t _num_root_segments;
|
||||
size_t _num_obj_arrays_logged;
|
||||
|
||||
AOTMapLogger::OopDataIterator* AOTMappedHeapWriter::oop_iterator(AOTMappedHeapInfo* heap_info) {
|
||||
class MappedWriterOopIterator : public AOTMappedHeapOopIterator {
|
||||
public:
|
||||
MappedWriterOopIterator(address buffer_start,
|
||||
address buffer_end,
|
||||
uint64_t buffer_start_narrow_oop,
|
||||
intptr_t buffer_to_requested_delta,
|
||||
address requested_base,
|
||||
address requested_start,
|
||||
int requested_shift,
|
||||
size_t num_root_segments)
|
||||
: _current(nullptr),
|
||||
_next(buffer_start),
|
||||
_buffer_start(buffer_start),
|
||||
_buffer_end(buffer_end),
|
||||
_buffer_start_narrow_oop(buffer_start_narrow_oop),
|
||||
_buffer_to_requested_delta(buffer_to_requested_delta),
|
||||
_requested_shift(requested_shift),
|
||||
_num_root_segments(num_root_segments),
|
||||
_num_obj_arrays_logged(0) {
|
||||
}
|
||||
size_t num_root_segments) :
|
||||
AOTMappedHeapOopIterator(buffer_start,
|
||||
buffer_end,
|
||||
requested_base,
|
||||
requested_start,
|
||||
requested_shift,
|
||||
num_root_segments) {}
|
||||
|
||||
AOTMapLogger::OopData capture(address buffered_addr) {
|
||||
AOTMapLogger::OopData capture(address buffered_addr) override {
|
||||
oopDesc* raw_oop = (oopDesc*)buffered_addr;
|
||||
size_t size = size_of_buffered_oop(buffered_addr);
|
||||
address requested_addr = buffered_addr_to_requested_addr(buffered_addr);
|
||||
@ -960,45 +943,6 @@ AOTMapLogger::OopDataIterator* AOTMappedHeapWriter::oop_iterator(ArchiveMappedHe
|
||||
size,
|
||||
false };
|
||||
}
|
||||
|
||||
bool has_next() override {
|
||||
return _next < _buffer_end;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
if (result._klass->is_objArray_klass()) {
|
||||
result._is_root_segment = _num_obj_arrays_logged++ < _num_root_segments;
|
||||
}
|
||||
_next = _current + result._size * BytesPerWord;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
uint64_t n = (uint64_t)(*addr);
|
||||
if (n == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
precond(n >= _buffer_start_narrow_oop);
|
||||
address buffer_addr = _buffer_start + ((n - _buffer_start_narrow_oop) << _requested_shift);
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
address requested_value = cast_from_oop<address>(*addr);
|
||||
if (requested_value == nullptr) {
|
||||
return null_data();
|
||||
} else {
|
||||
address buffer_addr = requested_value - _buffer_to_requested_delta;
|
||||
return capture(buffer_addr);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* roots() override {
|
||||
return new GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>();
|
||||
}
|
||||
};
|
||||
|
||||
MemRegion r = heap_info->buffer_region();
|
||||
@ -1008,17 +952,11 @@ AOTMapLogger::OopDataIterator* AOTMappedHeapWriter::oop_iterator(ArchiveMappedHe
|
||||
address requested_base = UseCompressedOops ? AOTMappedHeapWriter::narrow_oop_base() : (address)AOTMappedHeapWriter::NOCOOPS_REQUESTED_BASE;
|
||||
address requested_start = UseCompressedOops ? AOTMappedHeapWriter::buffered_addr_to_requested_addr(buffer_start) : requested_base;
|
||||
int requested_shift = AOTMappedHeapWriter::narrow_oop_shift();
|
||||
intptr_t buffer_to_requested_delta = requested_start - buffer_start;
|
||||
uint64_t buffer_start_narrow_oop = 0xdeadbeed;
|
||||
if (UseCompressedOops) {
|
||||
buffer_start_narrow_oop = (uint64_t)(pointer_delta(requested_start, requested_base, 1)) >> requested_shift;
|
||||
assert(buffer_start_narrow_oop < 0xffffffff, "sanity");
|
||||
}
|
||||
|
||||
return new MappedWriterOopIterator(buffer_start,
|
||||
buffer_end,
|
||||
buffer_start_narrow_oop,
|
||||
buffer_to_requested_delta,
|
||||
requested_base,
|
||||
requested_start,
|
||||
requested_shift,
|
||||
heap_info->root_segments().count());
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, 2026, 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
|
||||
@ -196,10 +196,10 @@ private:
|
||||
static int filler_array_length(size_t fill_bytes);
|
||||
static HeapWord* init_filler_array_at_buffer_top(int array_length, size_t fill_bytes);
|
||||
|
||||
static void set_requested_address_range(ArchiveMappedHeapInfo* info);
|
||||
static void set_requested_address_range(AOTMappedHeapInfo* info);
|
||||
static void mark_native_pointers(oop orig_obj);
|
||||
static void relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots, ArchiveMappedHeapInfo* info);
|
||||
static void compute_ptrmap(ArchiveMappedHeapInfo *info);
|
||||
static void relocate_embedded_oops(GrowableArrayCHeap<oop, mtClassShared>* roots, AOTMappedHeapInfo* info);
|
||||
static void compute_ptrmap(AOTMappedHeapInfo *info);
|
||||
static bool is_in_requested_range(oop o);
|
||||
static oop requested_obj_from_buffer_offset(size_t offset);
|
||||
|
||||
@ -229,7 +229,7 @@ public:
|
||||
static bool is_string_too_large_to_archive(oop string);
|
||||
static bool is_dumped_interned_string(oop o);
|
||||
static void add_to_dumped_interned_strings(oop string);
|
||||
static void write(GrowableArrayCHeap<oop, mtClassShared>*, ArchiveMappedHeapInfo* heap_info);
|
||||
static void write(GrowableArrayCHeap<oop, mtClassShared>*, AOTMappedHeapInfo* heap_info);
|
||||
static address requested_address(); // requested address of the lowest achived heap object
|
||||
static size_t get_filler_size_at(address buffered_addr);
|
||||
|
||||
@ -240,7 +240,7 @@ public:
|
||||
static Klass* real_klass_of_buffered_oop(address buffered_addr);
|
||||
static size_t size_of_buffered_oop(address buffered_addr);
|
||||
|
||||
static AOTMapLogger::OopDataIterator* oop_iterator(ArchiveMappedHeapInfo* heap_info);
|
||||
static AOTMapLogger::OopDataIterator* oop_iterator(AOTMappedHeapInfo* heap_info);
|
||||
};
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
#endif // SHARE_CDS_AOTMAPPEDHEAPWRITER_HPP
|
||||
|
||||
@ -661,8 +661,8 @@ void AOTMetaspace::rewrite_bytecodes_and_calculate_fingerprints(Thread* thread,
|
||||
|
||||
class VM_PopulateDumpSharedSpace : public VM_Operation {
|
||||
private:
|
||||
ArchiveMappedHeapInfo _mapped_heap_info;
|
||||
ArchiveStreamedHeapInfo _streamed_heap_info;
|
||||
AOTMappedHeapInfo _mapped_heap_info;
|
||||
AOTStreamedHeapInfo _streamed_heap_info;
|
||||
FileMapInfo* _map_info;
|
||||
StaticArchiveBuilder& _builder;
|
||||
|
||||
@ -682,8 +682,8 @@ public:
|
||||
bool skip_operation() const { return false; }
|
||||
|
||||
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
|
||||
ArchiveMappedHeapInfo* mapped_heap_info() { return &_mapped_heap_info; }
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info() { return &_streamed_heap_info; }
|
||||
AOTMappedHeapInfo* mapped_heap_info() { return &_mapped_heap_info; }
|
||||
AOTStreamedHeapInfo* streamed_heap_info() { return &_streamed_heap_info; }
|
||||
void doit(); // outline because gdb sucks
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
}; // class VM_PopulateDumpSharedSpace
|
||||
@ -1212,8 +1212,8 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
|
||||
bool AOTMetaspace::write_static_archive(ArchiveBuilder* builder,
|
||||
FileMapInfo* map_info,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info) {
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info) {
|
||||
// relocate the data so that it can be mapped to AOTMetaspace::requested_base_address()
|
||||
// without runtime relocation.
|
||||
builder->relocate_to_requested();
|
||||
@ -2106,7 +2106,7 @@ MapArchiveResult AOTMetaspace::map_archive(FileMapInfo* mapinfo, char* mapped_ba
|
||||
// Currently, only static archive uses early serialized data.
|
||||
char* buffer = mapinfo->early_serialized_data();
|
||||
intptr_t* array = (intptr_t*)buffer;
|
||||
ReadClosure rc(&array, (intptr_t)mapped_base_address);
|
||||
ReadClosure rc(&array, (address)mapped_base_address);
|
||||
early_serialize(&rc);
|
||||
}
|
||||
|
||||
@ -2152,7 +2152,7 @@ void AOTMetaspace::initialize_shared_spaces() {
|
||||
// shared string/symbol tables.
|
||||
char* buffer = static_mapinfo->serialized_data();
|
||||
intptr_t* array = (intptr_t*)buffer;
|
||||
ReadClosure rc(&array, (intptr_t)SharedBaseAddress);
|
||||
ReadClosure rc(&array, (address)SharedBaseAddress);
|
||||
serialize(&rc);
|
||||
|
||||
// Finish initializing the heap dump mode used in the archive
|
||||
@ -2164,7 +2164,7 @@ void AOTMetaspace::initialize_shared_spaces() {
|
||||
|
||||
if (dynamic_mapinfo != nullptr) {
|
||||
intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data();
|
||||
ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress);
|
||||
ReadClosure rc(&buffer, (address)SharedBaseAddress);
|
||||
DynamicArchive::serialize(&rc);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026, 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
|
||||
@ -33,8 +33,8 @@
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class ArchiveBuilder;
|
||||
class ArchiveMappedHeapInfo;
|
||||
class ArchiveStreamedHeapInfo;
|
||||
class AOTMappedHeapInfo;
|
||||
class AOTStreamedHeapInfo;
|
||||
class FileMapInfo;
|
||||
class Method;
|
||||
class outputStream;
|
||||
@ -192,8 +192,8 @@ private:
|
||||
static void open_output_mapinfo();
|
||||
static bool write_static_archive(ArchiveBuilder* builder,
|
||||
FileMapInfo* map_info,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info);
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info);
|
||||
static FileMapInfo* open_static_archive();
|
||||
static FileMapInfo* open_dynamic_archive();
|
||||
// use_requested_addr: If true (default), attempt to map at the address the
|
||||
|
||||
55
src/hotspot/share/cds/aotStreamedHeap.cpp
Normal file
55
src/hotspot/share/cds/aotStreamedHeap.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 "cds/aotStreamedHeap.hpp"
|
||||
|
||||
// Anything that goes in the header must be thoroughly purged from uninitialized memory
|
||||
// as it will be written to disk. Therefore, the constructors memset the memory to 0.
|
||||
// This is not the prettiest thing, but we need to know every byte is initialized,
|
||||
// including potential padding between fields.
|
||||
|
||||
AOTStreamedHeapHeader::AOTStreamedHeapHeader(size_t forwarding_offset,
|
||||
size_t roots_offset,
|
||||
size_t num_roots,
|
||||
size_t root_highest_object_index_table_offset,
|
||||
size_t num_archived_objects) {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
_forwarding_offset = forwarding_offset;
|
||||
_roots_offset = roots_offset;
|
||||
_num_roots = num_roots;
|
||||
_root_highest_object_index_table_offset = root_highest_object_index_table_offset;
|
||||
_num_archived_objects = num_archived_objects;
|
||||
}
|
||||
|
||||
AOTStreamedHeapHeader::AOTStreamedHeapHeader() {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
AOTStreamedHeapHeader AOTStreamedHeapInfo::create_header() {
|
||||
return AOTStreamedHeapHeader{_forwarding_offset,
|
||||
_roots_offset,
|
||||
_num_roots,
|
||||
_root_highest_object_index_table_offset,
|
||||
_num_archived_objects};
|
||||
}
|
||||
147
src/hotspot/share/cds/aotStreamedHeap.hpp
Normal file
147
src/hotspot/share/cds/aotStreamedHeap.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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 SHARE_CDS_AOTSTREAMEDHEAP_HPP
|
||||
#define SHARE_CDS_AOTSTREAMEDHEAP_HPP
|
||||
|
||||
#include "cds/aotMapLogger.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class AOTStreamedHeapHeader {
|
||||
size_t _forwarding_offset; // Offset of forwarding information in the heap region.
|
||||
size_t _roots_offset; // Start position for the roots
|
||||
size_t _root_highest_object_index_table_offset; // Offset of root dfs depth information
|
||||
size_t _num_roots; // Number of embedded roots
|
||||
size_t _num_archived_objects; // The number of archived heap objects
|
||||
|
||||
public:
|
||||
AOTStreamedHeapHeader();
|
||||
AOTStreamedHeapHeader(size_t forwarding_offset,
|
||||
size_t roots_offset,
|
||||
size_t num_roots,
|
||||
size_t root_highest_object_index_table_offset,
|
||||
size_t num_archived_objects);
|
||||
|
||||
size_t forwarding_offset() const { return _forwarding_offset; }
|
||||
size_t roots_offset() const { return _roots_offset; }
|
||||
size_t num_roots() const { return _num_roots; }
|
||||
size_t root_highest_object_index_table_offset() const { return _root_highest_object_index_table_offset; }
|
||||
size_t num_archived_objects() const { return _num_archived_objects; }
|
||||
|
||||
// This class is trivially copyable and assignable.
|
||||
AOTStreamedHeapHeader(const AOTStreamedHeapHeader&) = default;
|
||||
AOTStreamedHeapHeader& operator=(const AOTStreamedHeapHeader&) = default;
|
||||
};
|
||||
|
||||
class AOTStreamedHeapInfo {
|
||||
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
|
||||
CHeapBitMap _oopmap;
|
||||
size_t _roots_offset; // Offset of the HeapShared::roots() object, from the bottom
|
||||
// of the archived heap objects, in bytes.
|
||||
size_t _num_roots;
|
||||
|
||||
size_t _forwarding_offset; // Offset of forwarding information from the bottom
|
||||
size_t _root_highest_object_index_table_offset; // Offset to root dfs depth information
|
||||
size_t _num_archived_objects; // The number of archived objects written into the CDS archive.
|
||||
|
||||
public:
|
||||
AOTStreamedHeapInfo()
|
||||
: _buffer_region(),
|
||||
_oopmap(128, mtClassShared),
|
||||
_roots_offset(),
|
||||
_forwarding_offset(),
|
||||
_root_highest_object_index_table_offset(),
|
||||
_num_archived_objects() {}
|
||||
|
||||
bool is_used() { return !_buffer_region.is_empty(); }
|
||||
|
||||
void set_buffer_region(MemRegion r) { _buffer_region = r; }
|
||||
MemRegion buffer_region() { return _buffer_region; }
|
||||
char* buffer_start() { return (char*)_buffer_region.start(); }
|
||||
size_t buffer_byte_size() { return _buffer_region.byte_size(); }
|
||||
|
||||
CHeapBitMap* oopmap() { return &_oopmap; }
|
||||
void set_roots_offset(size_t n) { _roots_offset = n; }
|
||||
size_t roots_offset() { return _roots_offset; }
|
||||
void set_num_roots(size_t n) { _num_roots = n; }
|
||||
size_t num_roots() { return _num_roots; }
|
||||
void set_forwarding_offset(size_t n) { _forwarding_offset = n; }
|
||||
void set_root_highest_object_index_table_offset(size_t n) { _root_highest_object_index_table_offset = n; }
|
||||
void set_num_archived_objects(size_t n) { _num_archived_objects = n; }
|
||||
size_t num_archived_objects() { return _num_archived_objects; }
|
||||
|
||||
AOTStreamedHeapHeader create_header();
|
||||
};
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
class AOTStreamedHeapOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
protected:
|
||||
int _current;
|
||||
int _next;
|
||||
address _buffer_start;
|
||||
int _num_archived_objects;
|
||||
|
||||
public:
|
||||
AOTStreamedHeapOopIterator(address buffer_start,
|
||||
int num_archived_objects)
|
||||
: _current(0),
|
||||
_next(1),
|
||||
_buffer_start(buffer_start),
|
||||
_num_archived_objects(num_archived_objects) {}
|
||||
|
||||
virtual AOTMapLogger::OopData capture(int dfs_index) = 0;
|
||||
|
||||
bool has_next() override {
|
||||
return _next <= _num_archived_objects;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
_next = _current + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
int dfs_index = (int)(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
int dfs_index = (int)cast_from_oop<uintptr_t>(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
#endif // SHARE_CDS_AOTSTREAMEDHEAP_HPP
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, 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
|
||||
@ -1102,25 +1102,13 @@ void AOTStreamedHeapLoader::finish_initialization(FileMapInfo* static_mapinfo) {
|
||||
}
|
||||
|
||||
AOTMapLogger::OopDataIterator* AOTStreamedHeapLoader::oop_iterator(FileMapInfo* info, address buffer_start, address buffer_end) {
|
||||
class StreamedLoaderOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
private:
|
||||
int _current;
|
||||
int _next;
|
||||
|
||||
address _buffer_start;
|
||||
|
||||
int _num_archived_objects;
|
||||
|
||||
class StreamedLoaderOopIterator : public AOTStreamedHeapOopIterator {
|
||||
public:
|
||||
StreamedLoaderOopIterator(address buffer_start,
|
||||
int num_archived_objects)
|
||||
: _current(0),
|
||||
_next(1),
|
||||
_buffer_start(buffer_start),
|
||||
_num_archived_objects(num_archived_objects) {
|
||||
}
|
||||
: AOTStreamedHeapOopIterator(buffer_start, num_archived_objects) {}
|
||||
|
||||
AOTMapLogger::OopData capture(int dfs_index) {
|
||||
AOTMapLogger::OopData capture(int dfs_index) override {
|
||||
size_t buffered_offset = buffer_offset_for_object_index(dfs_index);
|
||||
address buffered_addr = _buffer_start + buffered_offset;
|
||||
oopDesc* raw_oop = (oopDesc*)buffered_addr;
|
||||
@ -1142,35 +1130,6 @@ AOTMapLogger::OopDataIterator* AOTStreamedHeapLoader::oop_iterator(FileMapInfo*
|
||||
false };
|
||||
}
|
||||
|
||||
bool has_next() override {
|
||||
return _next <= _num_archived_objects;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
_next = _current + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
int dfs_index = (int)(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
int dfs_index = (int)cast_from_oop<uintptr_t>(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* roots() override {
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* result = new GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>();
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, 2026, 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
|
||||
@ -163,7 +163,7 @@ void AOTStreamedHeapWriter::order_source_objs(GrowableArrayCHeap<oop, mtClassSha
|
||||
}
|
||||
|
||||
void AOTStreamedHeapWriter::write(GrowableArrayCHeap<oop, mtClassShared>* roots,
|
||||
ArchiveStreamedHeapInfo* heap_info) {
|
||||
AOTStreamedHeapInfo* heap_info) {
|
||||
assert(CDSConfig::is_dumping_heap(), "sanity");
|
||||
allocate_buffer();
|
||||
order_source_objs(roots);
|
||||
@ -453,7 +453,7 @@ static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bit
|
||||
}
|
||||
|
||||
// Update all oop fields embedded in the buffered objects
|
||||
void AOTStreamedHeapWriter::map_embedded_oops(ArchiveStreamedHeapInfo* heap_info) {
|
||||
void AOTStreamedHeapWriter::map_embedded_oops(AOTStreamedHeapInfo* heap_info) {
|
||||
size_t oopmap_unit = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
|
||||
size_t heap_region_byte_size = _buffer_used;
|
||||
heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit);
|
||||
@ -497,7 +497,7 @@ oop AOTStreamedHeapWriter::buffered_addr_to_source_obj(address buffered_addr) {
|
||||
return buffered_offset_to_source_obj(buffered_address_to_offset(buffered_addr));
|
||||
}
|
||||
|
||||
void AOTStreamedHeapWriter::populate_archive_heap_info(ArchiveStreamedHeapInfo* info) {
|
||||
void AOTStreamedHeapWriter::populate_archive_heap_info(AOTStreamedHeapInfo* info) {
|
||||
assert(!info->is_used(), "only set once");
|
||||
|
||||
size_t heap_region_byte_size = _buffer_used;
|
||||
@ -512,15 +512,9 @@ void AOTStreamedHeapWriter::populate_archive_heap_info(ArchiveStreamedHeapInfo*
|
||||
info->set_num_archived_objects((size_t)_source_objs->length());
|
||||
}
|
||||
|
||||
AOTMapLogger::OopDataIterator* AOTStreamedHeapWriter::oop_iterator(ArchiveStreamedHeapInfo* heap_info) {
|
||||
class StreamedWriterOopIterator : public AOTMapLogger::OopDataIterator {
|
||||
AOTMapLogger::OopDataIterator* AOTStreamedHeapWriter::oop_iterator(AOTStreamedHeapInfo* heap_info) {
|
||||
class StreamedWriterOopIterator : public AOTStreamedHeapOopIterator {
|
||||
private:
|
||||
int _current;
|
||||
int _next;
|
||||
|
||||
address _buffer_start;
|
||||
|
||||
int _num_archived_objects;
|
||||
int _num_archived_roots;
|
||||
int* _roots;
|
||||
|
||||
@ -529,15 +523,11 @@ AOTMapLogger::OopDataIterator* AOTStreamedHeapWriter::oop_iterator(ArchiveStream
|
||||
int num_archived_objects,
|
||||
int num_archived_roots,
|
||||
int* roots)
|
||||
: _current(0),
|
||||
_next(1),
|
||||
_buffer_start(buffer_start),
|
||||
_num_archived_objects(num_archived_objects),
|
||||
: AOTStreamedHeapOopIterator(buffer_start, num_archived_objects),
|
||||
_num_archived_roots(num_archived_roots),
|
||||
_roots(roots) {
|
||||
}
|
||||
_roots(roots) {}
|
||||
|
||||
AOTMapLogger::OopData capture(int dfs_index) {
|
||||
AOTMapLogger::OopData capture(int dfs_index) override {
|
||||
size_t buffered_offset = _dfs_to_archive_object_table[dfs_index];
|
||||
address buffered_addr = _buffer_start + buffered_offset;
|
||||
oop src_obj = AOTStreamedHeapWriter::buffered_offset_to_source_obj(buffered_offset);
|
||||
@ -561,35 +551,6 @@ AOTMapLogger::OopDataIterator* AOTStreamedHeapWriter::oop_iterator(ArchiveStream
|
||||
false };
|
||||
}
|
||||
|
||||
bool has_next() override {
|
||||
return _next <= _num_archived_objects;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData next() override {
|
||||
_current = _next;
|
||||
AOTMapLogger::OopData result = capture(_current);
|
||||
_next = _current + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(narrowOop* addr) override {
|
||||
int dfs_index = (int)(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
|
||||
AOTMapLogger::OopData obj_at(oop* addr) override {
|
||||
int dfs_index = (int)cast_from_oop<uintptr_t>(*addr);
|
||||
if (dfs_index == 0) {
|
||||
return null_data();
|
||||
} else {
|
||||
return capture(dfs_index);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* roots() override {
|
||||
GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>* result = new GrowableArrayCHeap<AOTMapLogger::OopData, mtClass>();
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, 2026, 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
|
||||
@ -117,7 +117,7 @@ class AOTStreamedHeapWriter : AllStatic {
|
||||
static void copy_forwarding_to_buffer();
|
||||
static void copy_roots_max_dfs_to_buffer(int roots_length);
|
||||
|
||||
static void map_embedded_oops(ArchiveStreamedHeapInfo* info);
|
||||
static void map_embedded_oops(AOTStreamedHeapInfo* info);
|
||||
static bool is_in_requested_range(oop o);
|
||||
static oop requested_obj_from_buffer_offset(size_t offset);
|
||||
|
||||
@ -131,14 +131,14 @@ class AOTStreamedHeapWriter : AllStatic {
|
||||
|
||||
static void update_header_for_buffered_addr(address buffered_addr, oop src_obj, Klass* src_klass);
|
||||
|
||||
static void populate_archive_heap_info(ArchiveStreamedHeapInfo* info);
|
||||
static void populate_archive_heap_info(AOTStreamedHeapInfo* info);
|
||||
|
||||
public:
|
||||
static void init() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
static void delete_tables_with_raw_oops();
|
||||
static void add_source_obj(oop src_obj);
|
||||
static void write(GrowableArrayCHeap<oop, mtClassShared>*, ArchiveStreamedHeapInfo* heap_info);
|
||||
static void write(GrowableArrayCHeap<oop, mtClassShared>*, AOTStreamedHeapInfo* heap_info);
|
||||
static address buffered_heap_roots_addr() {
|
||||
return offset_to_buffered_address<address>(_roots_offset);
|
||||
}
|
||||
@ -156,7 +156,7 @@ public:
|
||||
static oop buffered_offset_to_source_obj(size_t buffered_offset);
|
||||
static oop buffered_addr_to_source_obj(address buffered_addr);
|
||||
|
||||
static AOTMapLogger::OopDataIterator* oop_iterator(ArchiveStreamedHeapInfo* heap_info);
|
||||
static AOTMapLogger::OopDataIterator* oop_iterator(AOTStreamedHeapInfo* heap_info);
|
||||
};
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
#endif // SHARE_CDS_AOTSTREAMEDHEAPWRITER_HPP
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "cds/aotArtifactFinder.hpp"
|
||||
#include "cds/aotClassLinker.hpp"
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/aotMapLogger.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
@ -175,10 +176,10 @@ ArchiveBuilder::ArchiveBuilder() :
|
||||
_mapped_static_archive_bottom(nullptr),
|
||||
_mapped_static_archive_top(nullptr),
|
||||
_buffer_to_requested_delta(0),
|
||||
_pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive.
|
||||
_rw_region("rw", MAX_SHARED_DELTA),
|
||||
_ro_region("ro", MAX_SHARED_DELTA),
|
||||
_ac_region("ac", MAX_SHARED_DELTA),
|
||||
_pz_region("pz"), // protection zone -- used only during dumping; does NOT exist in cds archive.
|
||||
_rw_region("rw"),
|
||||
_ro_region("ro"),
|
||||
_ac_region("ac"),
|
||||
_ptrmap(mtClassShared),
|
||||
_rw_ptrmap(mtClassShared),
|
||||
_ro_ptrmap(mtClassShared),
|
||||
@ -990,16 +991,15 @@ void ArchiveBuilder::make_training_data_shareable() {
|
||||
_src_obj_table.iterate_all(clean_td);
|
||||
}
|
||||
|
||||
uintx ArchiveBuilder::buffer_to_offset(address p) const {
|
||||
size_t ArchiveBuilder::buffer_to_offset(address p) const {
|
||||
address requested_p = to_requested(p);
|
||||
assert(requested_p >= _requested_static_archive_bottom, "must be");
|
||||
return requested_p - _requested_static_archive_bottom;
|
||||
return pointer_delta(requested_p, _requested_static_archive_bottom, 1);
|
||||
}
|
||||
|
||||
uintx ArchiveBuilder::any_to_offset(address p) const {
|
||||
size_t ArchiveBuilder::any_to_offset(address p) const {
|
||||
if (is_in_mapped_static_archive(p)) {
|
||||
assert(CDSConfig::is_dumping_dynamic_archive(), "must be");
|
||||
return p - _mapped_static_archive_bottom;
|
||||
return pointer_delta(p, _mapped_static_archive_bottom, 1);
|
||||
}
|
||||
if (!is_in_buffer_space(p)) {
|
||||
// p must be a "source" address
|
||||
@ -1008,7 +1008,7 @@ uintx ArchiveBuilder::any_to_offset(address p) const {
|
||||
return buffer_to_offset(p);
|
||||
}
|
||||
|
||||
address ArchiveBuilder::offset_to_buffered_address(u4 offset) const {
|
||||
address ArchiveBuilder::offset_to_buffered_address(size_t offset) const {
|
||||
address requested_addr = _requested_static_archive_bottom + offset;
|
||||
address buffered_addr = requested_addr - _buffer_to_requested_delta;
|
||||
assert(is_in_buffer_space(buffered_addr), "bad offset");
|
||||
@ -1154,7 +1154,7 @@ void ArchiveBuilder::print_stats() {
|
||||
_alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used()));
|
||||
}
|
||||
|
||||
void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveMappedHeapInfo* mapped_heap_info, ArchiveStreamedHeapInfo* streamed_heap_info) {
|
||||
void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info) {
|
||||
// Make sure NUM_CDS_REGIONS (exported in cds.h) agrees with
|
||||
// AOTMetaspace::n_regions (internal to hotspot).
|
||||
assert(NUM_CDS_REGIONS == AOTMetaspace::n_regions, "sanity");
|
||||
@ -1213,8 +1213,8 @@ void ArchiveBuilder::count_relocated_pointer(bool tagged, bool nulled) {
|
||||
}
|
||||
|
||||
void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info) {
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info) {
|
||||
// Print statistics of all the regions
|
||||
const size_t bitmap_used = mapinfo->region_at(AOTMetaspace::bm)->used();
|
||||
const size_t bitmap_reserved = mapinfo->region_at(AOTMetaspace::bm)->used_aligned();
|
||||
|
||||
@ -39,8 +39,8 @@
|
||||
#include "utilities/hashTable.hpp"
|
||||
#include "utilities/resizableHashTable.hpp"
|
||||
|
||||
class ArchiveMappedHeapInfo;
|
||||
class ArchiveStreamedHeapInfo;
|
||||
class AOTMappedHeapInfo;
|
||||
class AOTStreamedHeapInfo;
|
||||
class CHeapBitMap;
|
||||
class FileMapInfo;
|
||||
class Klass;
|
||||
@ -247,8 +247,8 @@ private:
|
||||
} _relocated_ptr_info;
|
||||
|
||||
void print_region_stats(FileMapInfo *map_info,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info);
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info);
|
||||
void print_bitmap_region_stats(size_t size, size_t total_size);
|
||||
void print_heap_region_stats(char* start, size_t size, size_t total_size);
|
||||
|
||||
@ -329,49 +329,22 @@ public:
|
||||
return current()->buffer_to_requested_delta();
|
||||
}
|
||||
|
||||
inline static u4 to_offset_u4(uintx offset) {
|
||||
guarantee(offset <= MAX_SHARED_DELTA, "must be 32-bit offset " INTPTR_FORMAT, offset);
|
||||
return (u4)offset;
|
||||
}
|
||||
|
||||
public:
|
||||
static const uintx MAX_SHARED_DELTA = ArchiveUtils::MAX_SHARED_DELTA;;
|
||||
|
||||
// The address p points to an object inside the output buffer. When the archive is mapped
|
||||
// at the requested address, what's the offset of this object from _requested_static_archive_bottom?
|
||||
uintx buffer_to_offset(address p) const;
|
||||
size_t buffer_to_offset(address p) const;
|
||||
|
||||
// Same as buffer_to_offset, except that the address p points to either (a) an object
|
||||
// inside the output buffer, or (b), an object in the currently mapped static archive.
|
||||
uintx any_to_offset(address p) const;
|
||||
// Same as buffer_to_offset, except that the address p points to one of the following:
|
||||
// - an object in the ArchiveBuilder's buffer.
|
||||
// - an object in the currently mapped AOT cache rw/ro regions.
|
||||
// - an object that has been copied into the ArchiveBuilder's buffer.
|
||||
size_t any_to_offset(address p) const;
|
||||
|
||||
// The reverse of buffer_to_offset()
|
||||
address offset_to_buffered_address(u4 offset) const;
|
||||
address offset_to_buffered_address(size_t offset) const;
|
||||
|
||||
template <typename T>
|
||||
u4 buffer_to_offset_u4(T p) const {
|
||||
uintx offset = buffer_to_offset((address)p);
|
||||
return to_offset_u4(offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
u4 any_to_offset_u4(T p) const {
|
||||
assert(p != nullptr, "must not be null");
|
||||
uintx offset = any_to_offset((address)p);
|
||||
return to_offset_u4(offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
u4 any_or_null_to_offset_u4(T p) const {
|
||||
if (p == nullptr) {
|
||||
return 0;
|
||||
} else {
|
||||
return any_to_offset_u4<T>(p);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T offset_to_buffered(u4 offset) const {
|
||||
T offset_to_buffered(size_t offset) const {
|
||||
return (T)offset_to_buffered_address(offset);
|
||||
}
|
||||
|
||||
@ -438,8 +411,8 @@ public:
|
||||
void make_training_data_shareable();
|
||||
void relocate_to_requested();
|
||||
void write_archive(FileMapInfo* mapinfo,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info);
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info);
|
||||
void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,
|
||||
bool read_only, bool allow_exec);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, 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
|
||||
@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
@ -201,13 +202,13 @@ char* DumpRegion::expand_top_to(char* newtop) {
|
||||
commit_to(newtop);
|
||||
_top = newtop;
|
||||
|
||||
if (_max_delta > 0) {
|
||||
if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(_base)) {
|
||||
uintx delta = ArchiveBuilder::current()->buffer_to_offset((address)(newtop-1));
|
||||
if (delta > _max_delta) {
|
||||
if (delta > AOTCompressedPointers::MaxMetadataOffsetBytes) {
|
||||
// This is just a sanity check and should not appear in any real world usage. This
|
||||
// happens only if you allocate more than 2GB of shared objects and would require
|
||||
// millions of shared classes.
|
||||
aot_log_error(aot)("Out of memory in the CDS archive: Please reduce the number of shared classes.");
|
||||
aot_log_error(aot)("Out of memory in the %s: Please reduce the number of shared classes.", CDSConfig::type_of_archive_being_written());
|
||||
AOTMetaspace::unrecoverable_writing_error();
|
||||
}
|
||||
}
|
||||
@ -331,9 +332,8 @@ void WriteClosure::do_ptr(void** p) {
|
||||
|
||||
void ReadClosure::do_ptr(void** p) {
|
||||
assert(*p == nullptr, "initializing previous initialized pointer.");
|
||||
intptr_t obj = nextPtr();
|
||||
assert(obj >= 0, "sanity.");
|
||||
*p = (obj != 0) ? (void*)(_base_address + obj) : (void*)obj;
|
||||
u4 narrowp = checked_cast<u4>(nextPtr());
|
||||
*p = AOTCompressedPointers::decode<void*>(cast_from_u4(narrowp), _base_address);
|
||||
}
|
||||
|
||||
void ReadClosure::do_u4(u4* p) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, 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
|
||||
@ -153,7 +153,6 @@ private:
|
||||
char* _base;
|
||||
char* _top;
|
||||
char* _end;
|
||||
uintx _max_delta;
|
||||
bool _is_packed;
|
||||
ReservedSpace* _rs;
|
||||
VirtualSpace* _vs;
|
||||
@ -161,9 +160,9 @@ private:
|
||||
void commit_to(char* newtop);
|
||||
|
||||
public:
|
||||
DumpRegion(const char* name, uintx max_delta = 0)
|
||||
DumpRegion(const char* name)
|
||||
: _name(name), _base(nullptr), _top(nullptr), _end(nullptr),
|
||||
_max_delta(max_delta), _is_packed(false),
|
||||
_is_packed(false),
|
||||
_rs(nullptr), _vs(nullptr) {}
|
||||
|
||||
char* expand_top_to(char* newtop);
|
||||
@ -237,13 +236,13 @@ public:
|
||||
class ReadClosure : public SerializeClosure {
|
||||
private:
|
||||
intptr_t** _ptr_array;
|
||||
intptr_t _base_address;
|
||||
address _base_address;
|
||||
inline intptr_t nextPtr() {
|
||||
return *(*_ptr_array)++;
|
||||
}
|
||||
|
||||
public:
|
||||
ReadClosure(intptr_t** ptr_array, intptr_t base_address) :
|
||||
ReadClosure(intptr_t** ptr_array, address base_address) :
|
||||
_ptr_array(ptr_array), _base_address(base_address) {}
|
||||
|
||||
void do_ptr(void** p);
|
||||
@ -260,7 +259,6 @@ class ArchiveUtils {
|
||||
template <typename T> static Array<T>* archive_ptr_array(GrowableArray<T>* tmp_array);
|
||||
|
||||
public:
|
||||
static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
|
||||
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
|
||||
static bool has_aot_initialized_mirror(InstanceKlass* src_ik);
|
||||
|
||||
@ -273,50 +271,6 @@ public:
|
||||
static Array<T>* archive_array(GrowableArray<T>* tmp_array) {
|
||||
return archive_ptr_array(tmp_array);
|
||||
}
|
||||
|
||||
// The following functions translate between a u4 offset and an address in the
|
||||
// the range of the mapped CDS archive (e.g., Metaspace::in_aot_cache()).
|
||||
// Since the first 16 bytes in this range are dummy data (see ArchiveBuilder::reserve_buffer()),
|
||||
// we know that offset 0 never represents a valid object. As a result, an offset of 0
|
||||
// is used to encode a nullptr.
|
||||
//
|
||||
// Use the "archived_address_or_null" variants if a nullptr may be encoded.
|
||||
|
||||
// offset must represent an object of type T in the mapped shared space. Return
|
||||
// a direct pointer to this object.
|
||||
template <typename T> T static offset_to_archived_address(u4 offset) {
|
||||
assert(offset != 0, "sanity");
|
||||
T p = (T)(SharedBaseAddress + offset);
|
||||
assert(Metaspace::in_aot_cache(p), "must be");
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T> T static offset_to_archived_address_or_null(u4 offset) {
|
||||
if (offset == 0) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return offset_to_archived_address<T>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// p must be an archived object. Get its offset from SharedBaseAddress
|
||||
template <typename T> static u4 archived_address_to_offset(T p) {
|
||||
uintx pn = (uintx)p;
|
||||
uintx base = (uintx)SharedBaseAddress;
|
||||
assert(Metaspace::in_aot_cache(p), "must be");
|
||||
assert(pn > base, "sanity"); // No valid object is stored at 0 offset from SharedBaseAddress
|
||||
uintx offset = pn - base;
|
||||
assert(offset <= MAX_SHARED_DELTA, "range check");
|
||||
return static_cast<u4>(offset);
|
||||
}
|
||||
|
||||
template <typename T> static u4 archived_address_or_null_to_offset(T p) {
|
||||
if (p == nullptr) {
|
||||
return 0;
|
||||
} else {
|
||||
return archived_address_to_offset<T>(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class HeapRootSegments {
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "cds/aotArtifactFinder.hpp"
|
||||
#include "cds/aotClassLinker.hpp"
|
||||
#include "cds/aotClassLocation.hpp"
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
@ -75,13 +76,13 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name);
|
||||
u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name);
|
||||
u4 a_narrowp = cast_to_u4(AOTCompressedPointers::encode_not_null(a_name));
|
||||
u4 b_narrowp = cast_to_u4(AOTCompressedPointers::encode_not_null(b_name));
|
||||
|
||||
if (a_offset < b_offset) {
|
||||
if (a_narrowp < b_narrowp) {
|
||||
return -1;
|
||||
} else {
|
||||
assert(a_offset > b_offset, "must be");
|
||||
assert(a_narrowp > b_narrowp, "must be");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, 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
|
||||
@ -298,11 +298,11 @@ void FileMapHeader::print(outputStream* st) {
|
||||
st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs);
|
||||
st->print_cr("- narrow_klass_pointer_bits: %d", _narrow_klass_pointer_bits);
|
||||
st->print_cr("- narrow_klass_shift: %d", _narrow_klass_shift);
|
||||
st->print_cr("- cloned_vtables_offset: 0x%zx", _cloned_vtables_offset);
|
||||
st->print_cr("- early_serialized_data_offset: 0x%zx", _early_serialized_data_offset);
|
||||
st->print_cr("- serialized_data_offset: 0x%zx", _serialized_data_offset);
|
||||
st->print_cr("- cloned_vtables: %u", cast_to_u4(_cloned_vtables));
|
||||
st->print_cr("- early_serialized_data: %u", cast_to_u4(_early_serialized_data));
|
||||
st->print_cr("- serialized_data: %u", cast_to_u4(_serialized_data));
|
||||
st->print_cr("- jvm_ident: %s", _jvm_ident);
|
||||
st->print_cr("- class_location_config_offset: 0x%zx", _class_location_config_offset);
|
||||
st->print_cr("- class_location_config: %d", cast_to_u4(_class_location_config));
|
||||
st->print_cr("- verify_local: %d", _verify_local);
|
||||
st->print_cr("- verify_remote: %d", _verify_remote);
|
||||
st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes);
|
||||
@ -974,8 +974,8 @@ size_t FileMapInfo::remove_bitmap_zeros(CHeapBitMap* map) {
|
||||
|
||||
char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap,
|
||||
CHeapBitMap* ro_ptrmap,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info,
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info,
|
||||
size_t &size_in_bytes) {
|
||||
size_t removed_rw_leading_zeros = remove_bitmap_zeros(rw_ptrmap);
|
||||
size_t removed_ro_leading_zeros = remove_bitmap_zeros(ro_ptrmap);
|
||||
@ -1035,7 +1035,7 @@ char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap,
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
size_t FileMapInfo::write_mapped_heap_region(ArchiveMappedHeapInfo* heap_info) {
|
||||
size_t FileMapInfo::write_mapped_heap_region(AOTMappedHeapInfo* heap_info) {
|
||||
char* buffer_start = heap_info->buffer_start();
|
||||
size_t buffer_size = heap_info->buffer_byte_size();
|
||||
write_region(AOTMetaspace::hp, buffer_start, buffer_size, false, false);
|
||||
@ -1043,7 +1043,7 @@ size_t FileMapInfo::write_mapped_heap_region(ArchiveMappedHeapInfo* heap_info) {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
size_t FileMapInfo::write_streamed_heap_region(ArchiveStreamedHeapInfo* heap_info) {
|
||||
size_t FileMapInfo::write_streamed_heap_region(AOTStreamedHeapInfo* heap_info) {
|
||||
char* buffer_start = heap_info->buffer_start();
|
||||
size_t buffer_size = heap_info->buffer_byte_size();
|
||||
write_region(AOTMetaspace::hp, buffer_start, buffer_size, true, false);
|
||||
@ -1325,9 +1325,7 @@ char* FileMapInfo::map_auxiliary_region(int region_index, bool read_only) {
|
||||
|
||||
if (VerifySharedSpaces && !r->check_region_crc(mapped_base)) {
|
||||
aot_log_error(aot)("region %d CRC error", region_index);
|
||||
if (!os::unmap_memory(mapped_base, r->used_aligned())) {
|
||||
fatal("os::unmap_memory of region %d failed", region_index);
|
||||
}
|
||||
os::unmap_memory(mapped_base, r->used_aligned());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1654,9 +1652,7 @@ void FileMapInfo::unmap_region(int i) {
|
||||
// is released. Zero it so that we don't accidentally read its content.
|
||||
aot_log_info(aot)("Region #%d (%s) is in a reserved space, it will be freed when the space is released", i, shared_region_name[i]);
|
||||
} else {
|
||||
if (!os::unmap_memory(mapped_base, size)) {
|
||||
fatal("os::unmap_memory failed");
|
||||
}
|
||||
os::unmap_memory(mapped_base, size);
|
||||
}
|
||||
}
|
||||
r->set_mapped_base(nullptr);
|
||||
@ -1767,10 +1763,6 @@ void FileMapInfo::print(outputStream* st) const {
|
||||
}
|
||||
}
|
||||
|
||||
void FileMapHeader::set_as_offset(char* p, size_t *offset) {
|
||||
*offset = ArchiveBuilder::current()->any_to_offset((address)p);
|
||||
}
|
||||
|
||||
int FileMapHeader::compute_crc() {
|
||||
char* start = (char*)this;
|
||||
// start computing from the field after _header_size to end of base archive name.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, 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
|
||||
@ -25,7 +25,10 @@
|
||||
#ifndef SHARE_CDS_FILEMAP_HPP
|
||||
#define SHARE_CDS_FILEMAP_HPP
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotMappedHeap.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/aotStreamedHeap.hpp"
|
||||
#include "cds/archiveUtils.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "include/cds.h"
|
||||
@ -102,7 +105,7 @@ public:
|
||||
class FileMapHeader: private CDSFileMapHeaderBase {
|
||||
friend class CDSConstants;
|
||||
friend class VMStructs;
|
||||
|
||||
using narrowPtr = AOTCompressedPointers::narrowPtr;
|
||||
private:
|
||||
// The following fields record the states of the VM during dump time.
|
||||
// They are compared with the runtime states to see if the archive
|
||||
@ -120,16 +123,16 @@ private:
|
||||
bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers
|
||||
int _narrow_klass_pointer_bits; // save number of bits in narrowKlass
|
||||
int _narrow_klass_shift; // save shift width used to pre-compute narrowKlass IDs in archived heap objects
|
||||
size_t _cloned_vtables_offset; // The address of the first cloned vtable
|
||||
size_t _early_serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
narrowPtr _cloned_vtables; // The address of the first cloned vtable
|
||||
narrowPtr _early_serialized_data; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
narrowPtr _serialized_data; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
|
||||
// The following fields are all sanity checks for whether this archive
|
||||
// will function correctly with this JVM and the bootclasspath it's
|
||||
// invoked with.
|
||||
char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump
|
||||
|
||||
size_t _class_location_config_offset;
|
||||
narrowPtr _class_location_config;
|
||||
|
||||
bool _verify_local; // BytecodeVerificationLocal setting
|
||||
bool _verify_remote; // BytecodeVerificationRemote setting
|
||||
@ -144,8 +147,8 @@ private:
|
||||
size_t _rw_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the rw region
|
||||
size_t _ro_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the ro region
|
||||
|
||||
ArchiveMappedHeapHeader _mapped_heap_header;
|
||||
ArchiveStreamedHeapHeader _streamed_heap_header;
|
||||
AOTMappedHeapHeader _mapped_heap_header;
|
||||
AOTStreamedHeapHeader _streamed_heap_header;
|
||||
|
||||
// The following are parameters that affect MethodData layout.
|
||||
u1 _compiler_type;
|
||||
@ -158,12 +161,8 @@ private:
|
||||
bool _type_profile_casts;
|
||||
int _spec_trap_limit_extra_entries;
|
||||
|
||||
template <typename T> T from_mapped_offset(size_t offset) const {
|
||||
return (T)(mapped_base_address() + offset);
|
||||
}
|
||||
void set_as_offset(char* p, size_t *offset);
|
||||
template <typename T> void set_as_offset(T p, size_t *offset) {
|
||||
set_as_offset((char*)p, offset);
|
||||
template <typename T> T decode(narrowPtr narrowp) const {
|
||||
return AOTCompressedPointers::decode_not_null<T>(narrowp, reinterpret_cast<address>(mapped_base_address()));
|
||||
}
|
||||
|
||||
public:
|
||||
@ -191,9 +190,9 @@ public:
|
||||
bool compact_headers() const { return _compact_headers; }
|
||||
uintx max_heap_size() const { return _max_heap_size; }
|
||||
CompressedOops::Mode narrow_oop_mode() const { return _narrow_oop_mode; }
|
||||
char* cloned_vtables() const { return from_mapped_offset<char*>(_cloned_vtables_offset); }
|
||||
char* early_serialized_data() const { return from_mapped_offset<char*>(_early_serialized_data_offset); }
|
||||
char* serialized_data() const { return from_mapped_offset<char*>(_serialized_data_offset); }
|
||||
char* cloned_vtables() const { return decode<char*>(_cloned_vtables); }
|
||||
char* early_serialized_data() const { return decode<char*>(_early_serialized_data); }
|
||||
char* serialized_data() const { return decode<char*>(_serialized_data); }
|
||||
bool object_streaming_mode() const { return _object_streaming_mode; }
|
||||
const char* jvm_ident() const { return _jvm_ident; }
|
||||
char* requested_base_address() const { return _requested_base_address; }
|
||||
@ -209,16 +208,16 @@ public:
|
||||
size_t ro_ptrmap_start_pos() const { return _ro_ptrmap_start_pos; }
|
||||
|
||||
// Heap archiving
|
||||
const ArchiveMappedHeapHeader* mapped_heap() const { return &_mapped_heap_header; }
|
||||
const ArchiveStreamedHeapHeader* streamed_heap() const { return &_streamed_heap_header; }
|
||||
const AOTMappedHeapHeader* mapped_heap() const { return &_mapped_heap_header; }
|
||||
const AOTStreamedHeapHeader* streamed_heap() const { return &_streamed_heap_header; }
|
||||
|
||||
void set_streamed_heap_header(ArchiveStreamedHeapHeader header) { _streamed_heap_header = header; }
|
||||
void set_mapped_heap_header(ArchiveMappedHeapHeader header) { _mapped_heap_header = header; }
|
||||
void set_streamed_heap_header(AOTStreamedHeapHeader header) { _streamed_heap_header = header; }
|
||||
void set_mapped_heap_header(AOTMappedHeapHeader header) { _mapped_heap_header = header; }
|
||||
|
||||
void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; }
|
||||
void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); }
|
||||
void set_early_serialized_data(char* p) { set_as_offset(p, &_early_serialized_data_offset); }
|
||||
void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); }
|
||||
void set_cloned_vtables(char* p) { _cloned_vtables = AOTCompressedPointers::encode_not_null(p); }
|
||||
void set_early_serialized_data(char* p) { _early_serialized_data = AOTCompressedPointers::encode_not_null(p); }
|
||||
void set_serialized_data(char* p) { _serialized_data = AOTCompressedPointers::encode_not_null(p); }
|
||||
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
|
||||
void set_rw_ptrmap_start_pos(size_t n) { _rw_ptrmap_start_pos = n; }
|
||||
void set_ro_ptrmap_start_pos(size_t n) { _ro_ptrmap_start_pos = n; }
|
||||
@ -226,11 +225,11 @@ public:
|
||||
void copy_base_archive_name(const char* name);
|
||||
|
||||
void set_class_location_config(AOTClassLocationConfig* table) {
|
||||
set_as_offset(table, &_class_location_config_offset);
|
||||
_class_location_config = AOTCompressedPointers::encode_not_null(table);
|
||||
}
|
||||
|
||||
AOTClassLocationConfig* class_location_config() {
|
||||
return from_mapped_offset<AOTClassLocationConfig*>(_class_location_config_offset);
|
||||
return decode<AOTClassLocationConfig*>(_class_location_config);
|
||||
}
|
||||
|
||||
void set_requested_base(char* b) {
|
||||
@ -309,8 +308,8 @@ public:
|
||||
uintx max_heap_size() const { return header()->max_heap_size(); }
|
||||
size_t core_region_alignment() const { return header()->core_region_alignment(); }
|
||||
|
||||
const ArchiveMappedHeapHeader* mapped_heap() const { return header()->mapped_heap(); }
|
||||
const ArchiveStreamedHeapHeader* streamed_heap() const { return header()->streamed_heap(); }
|
||||
const AOTMappedHeapHeader* mapped_heap() const { return header()->mapped_heap(); }
|
||||
const AOTStreamedHeapHeader* streamed_heap() const { return header()->streamed_heap(); }
|
||||
|
||||
bool object_streaming_mode() const { return header()->object_streaming_mode(); }
|
||||
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
|
||||
@ -372,11 +371,11 @@ public:
|
||||
size_t remove_bitmap_zeros(CHeapBitMap* map);
|
||||
char* write_bitmap_region(CHeapBitMap* rw_ptrmap,
|
||||
CHeapBitMap* ro_ptrmap,
|
||||
ArchiveMappedHeapInfo* mapped_heap_info,
|
||||
ArchiveStreamedHeapInfo* streamed_heap_info,
|
||||
AOTMappedHeapInfo* mapped_heap_info,
|
||||
AOTStreamedHeapInfo* streamed_heap_info,
|
||||
size_t &size_in_bytes);
|
||||
size_t write_mapped_heap_region(ArchiveMappedHeapInfo* heap_info) NOT_CDS_JAVA_HEAP_RETURN_(0);
|
||||
size_t write_streamed_heap_region(ArchiveStreamedHeapInfo* heap_info) NOT_CDS_JAVA_HEAP_RETURN_(0);
|
||||
size_t write_mapped_heap_region(AOTMappedHeapInfo* heap_info) NOT_CDS_JAVA_HEAP_RETURN_(0);
|
||||
size_t write_streamed_heap_region(AOTStreamedHeapInfo* heap_info) NOT_CDS_JAVA_HEAP_RETURN_(0);
|
||||
void write_bytes(const void* buffer, size_t count);
|
||||
void write_bytes_aligned(const void* buffer, size_t count);
|
||||
size_t read_bytes(void* buffer, size_t count);
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "cds/aotArtifactFinder.hpp"
|
||||
#include "cds/aotClassInitializer.hpp"
|
||||
#include "cds/aotClassLocation.hpp"
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotLogging.hpp"
|
||||
#include "cds/aotMappedHeapLoader.hpp"
|
||||
#include "cds/aotMappedHeapWriter.hpp"
|
||||
@ -95,55 +96,6 @@ struct ArchivableStaticFieldInfo {
|
||||
}
|
||||
};
|
||||
|
||||
// Anything that goes in the header must be thoroughly purged from uninitialized memory
|
||||
// as it will be written to disk. Therefore, the constructors memset the memory to 0.
|
||||
// This is not the prettiest thing, but we need to know every byte is initialized,
|
||||
// including potential padding between fields.
|
||||
|
||||
ArchiveMappedHeapHeader::ArchiveMappedHeapHeader(size_t ptrmap_start_pos,
|
||||
size_t oopmap_start_pos,
|
||||
HeapRootSegments root_segments) {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
_ptrmap_start_pos = ptrmap_start_pos;
|
||||
_oopmap_start_pos = oopmap_start_pos;
|
||||
_root_segments = root_segments;
|
||||
}
|
||||
|
||||
ArchiveMappedHeapHeader::ArchiveMappedHeapHeader() {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
ArchiveMappedHeapHeader ArchiveMappedHeapInfo::create_header() {
|
||||
return ArchiveMappedHeapHeader{_ptrmap_start_pos,
|
||||
_oopmap_start_pos,
|
||||
_root_segments};
|
||||
}
|
||||
|
||||
ArchiveStreamedHeapHeader::ArchiveStreamedHeapHeader(size_t forwarding_offset,
|
||||
size_t roots_offset,
|
||||
size_t num_roots,
|
||||
size_t root_highest_object_index_table_offset,
|
||||
size_t num_archived_objects) {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
_forwarding_offset = forwarding_offset;
|
||||
_roots_offset = roots_offset;
|
||||
_num_roots = num_roots;
|
||||
_root_highest_object_index_table_offset = root_highest_object_index_table_offset;
|
||||
_num_archived_objects = num_archived_objects;
|
||||
}
|
||||
|
||||
ArchiveStreamedHeapHeader::ArchiveStreamedHeapHeader() {
|
||||
memset((char*)this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
ArchiveStreamedHeapHeader ArchiveStreamedHeapInfo::create_header() {
|
||||
return ArchiveStreamedHeapHeader{_forwarding_offset,
|
||||
_roots_offset,
|
||||
_num_roots,
|
||||
_root_highest_object_index_table_offset,
|
||||
_num_archived_objects};
|
||||
}
|
||||
|
||||
HeapArchiveMode HeapShared::_heap_load_mode = HeapArchiveMode::_uninitialized;
|
||||
HeapArchiveMode HeapShared::_heap_write_mode = HeapArchiveMode::_uninitialized;
|
||||
|
||||
@ -892,7 +844,7 @@ void HeapShared::end_scanning_for_oops() {
|
||||
delete_seen_objects_table();
|
||||
}
|
||||
|
||||
void HeapShared::write_heap(ArchiveMappedHeapInfo* mapped_heap_info, ArchiveStreamedHeapInfo* streamed_heap_info) {
|
||||
void HeapShared::write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info) {
|
||||
{
|
||||
NoSafepointVerifier nsv;
|
||||
CDSHeapVerifier::verify();
|
||||
@ -1197,8 +1149,7 @@ public:
|
||||
ArchivedKlassSubGraphInfoRecord* record = HeapShared::archive_subgraph_info(&info);
|
||||
Klass* buffered_k = ArchiveBuilder::get_buffered_klass(klass);
|
||||
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)buffered_k);
|
||||
u4 delta = ArchiveBuilder::current()->any_to_offset_u4(record);
|
||||
_writer->add(hash, delta);
|
||||
_writer->add(hash, AOTCompressedPointers::encode_not_null(record));
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
|
||||
@ -142,129 +142,6 @@ enum class HeapArchiveMode {
|
||||
_streaming
|
||||
};
|
||||
|
||||
class ArchiveMappedHeapHeader {
|
||||
size_t _ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
|
||||
size_t _oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
|
||||
HeapRootSegments _root_segments; // Heap root segments info
|
||||
|
||||
public:
|
||||
ArchiveMappedHeapHeader();
|
||||
ArchiveMappedHeapHeader(size_t ptrmap_start_pos,
|
||||
size_t oopmap_start_pos,
|
||||
HeapRootSegments root_segments);
|
||||
|
||||
size_t ptrmap_start_pos() const { return _ptrmap_start_pos; }
|
||||
size_t oopmap_start_pos() const { return _oopmap_start_pos; }
|
||||
HeapRootSegments root_segments() const { return _root_segments; }
|
||||
|
||||
// This class is trivially copyable and assignable.
|
||||
ArchiveMappedHeapHeader(const ArchiveMappedHeapHeader&) = default;
|
||||
ArchiveMappedHeapHeader& operator=(const ArchiveMappedHeapHeader&) = default;
|
||||
};
|
||||
|
||||
|
||||
class ArchiveStreamedHeapHeader {
|
||||
size_t _forwarding_offset; // Offset of forwarding information in the heap region.
|
||||
size_t _roots_offset; // Start position for the roots
|
||||
size_t _root_highest_object_index_table_offset; // Offset of root dfs depth information
|
||||
size_t _num_roots; // Number of embedded roots
|
||||
size_t _num_archived_objects; // The number of archived heap objects
|
||||
|
||||
public:
|
||||
ArchiveStreamedHeapHeader();
|
||||
ArchiveStreamedHeapHeader(size_t forwarding_offset,
|
||||
size_t roots_offset,
|
||||
size_t num_roots,
|
||||
size_t root_highest_object_index_table_offset,
|
||||
size_t num_archived_objects);
|
||||
|
||||
size_t forwarding_offset() const { return _forwarding_offset; }
|
||||
size_t roots_offset() const { return _roots_offset; }
|
||||
size_t num_roots() const { return _num_roots; }
|
||||
size_t root_highest_object_index_table_offset() const { return _root_highest_object_index_table_offset; }
|
||||
size_t num_archived_objects() const { return _num_archived_objects; }
|
||||
|
||||
// This class is trivially copyable and assignable.
|
||||
ArchiveStreamedHeapHeader(const ArchiveStreamedHeapHeader&) = default;
|
||||
ArchiveStreamedHeapHeader& operator=(const ArchiveStreamedHeapHeader&) = default;
|
||||
};
|
||||
|
||||
class ArchiveMappedHeapInfo {
|
||||
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
|
||||
CHeapBitMap _oopmap;
|
||||
CHeapBitMap _ptrmap;
|
||||
HeapRootSegments _root_segments;
|
||||
size_t _oopmap_start_pos; // How many zeros were removed from the beginning of the bit map?
|
||||
size_t _ptrmap_start_pos; // How many zeros were removed from the beginning of the bit map?
|
||||
|
||||
public:
|
||||
ArchiveMappedHeapInfo() :
|
||||
_buffer_region(),
|
||||
_oopmap(128, mtClassShared),
|
||||
_ptrmap(128, mtClassShared),
|
||||
_root_segments(),
|
||||
_oopmap_start_pos(),
|
||||
_ptrmap_start_pos() {}
|
||||
bool is_used() { return !_buffer_region.is_empty(); }
|
||||
|
||||
MemRegion buffer_region() { return _buffer_region; }
|
||||
void set_buffer_region(MemRegion r) { _buffer_region = r; }
|
||||
|
||||
char* buffer_start() { return (char*)_buffer_region.start(); }
|
||||
size_t buffer_byte_size() { return _buffer_region.byte_size(); }
|
||||
|
||||
CHeapBitMap* oopmap() { return &_oopmap; }
|
||||
CHeapBitMap* ptrmap() { return &_ptrmap; }
|
||||
|
||||
void set_oopmap_start_pos(size_t start_pos) { _oopmap_start_pos = start_pos; }
|
||||
void set_ptrmap_start_pos(size_t start_pos) { _ptrmap_start_pos = start_pos; }
|
||||
|
||||
void set_root_segments(HeapRootSegments segments) { _root_segments = segments; };
|
||||
HeapRootSegments root_segments() { return _root_segments; }
|
||||
|
||||
ArchiveMappedHeapHeader create_header();
|
||||
};
|
||||
|
||||
class ArchiveStreamedHeapInfo {
|
||||
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
|
||||
CHeapBitMap _oopmap;
|
||||
size_t _roots_offset; // Offset of the HeapShared::roots() object, from the bottom
|
||||
// of the archived heap objects, in bytes.
|
||||
size_t _num_roots;
|
||||
|
||||
size_t _forwarding_offset; // Offset of forwarding information from the bottom
|
||||
size_t _root_highest_object_index_table_offset; // Offset to root dfs depth information
|
||||
size_t _num_archived_objects; // The number of archived objects written into the CDS archive.
|
||||
|
||||
public:
|
||||
ArchiveStreamedHeapInfo()
|
||||
: _buffer_region(),
|
||||
_oopmap(128, mtClassShared),
|
||||
_roots_offset(),
|
||||
_forwarding_offset(),
|
||||
_root_highest_object_index_table_offset(),
|
||||
_num_archived_objects() {}
|
||||
|
||||
bool is_used() { return !_buffer_region.is_empty(); }
|
||||
|
||||
void set_buffer_region(MemRegion r) { _buffer_region = r; }
|
||||
MemRegion buffer_region() { return _buffer_region; }
|
||||
char* buffer_start() { return (char*)_buffer_region.start(); }
|
||||
size_t buffer_byte_size() { return _buffer_region.byte_size(); }
|
||||
|
||||
CHeapBitMap* oopmap() { return &_oopmap; }
|
||||
void set_roots_offset(size_t n) { _roots_offset = n; }
|
||||
size_t roots_offset() { return _roots_offset; }
|
||||
void set_num_roots(size_t n) { _num_roots = n; }
|
||||
size_t num_roots() { return _num_roots; }
|
||||
void set_forwarding_offset(size_t n) { _forwarding_offset = n; }
|
||||
void set_root_highest_object_index_table_offset(size_t n) { _root_highest_object_index_table_offset = n; }
|
||||
void set_num_archived_objects(size_t n) { _num_archived_objects = n; }
|
||||
size_t num_archived_objects() { return _num_archived_objects; }
|
||||
|
||||
ArchiveStreamedHeapHeader create_header();
|
||||
};
|
||||
|
||||
class HeapShared: AllStatic {
|
||||
friend class VerifySharedOopClosure;
|
||||
|
||||
@ -575,7 +452,7 @@ private:
|
||||
public:
|
||||
static void finish_materialize_objects() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
static void write_heap(ArchiveMappedHeapInfo* mapped_heap_info, ArchiveStreamedHeapInfo* streamed_heap_info) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static objArrayOop scratch_resolved_references(ConstantPool* src);
|
||||
static void add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void init_dumping() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "cds/aotClassFilter.hpp"
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
@ -52,7 +53,7 @@
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
|
||||
GrowableArrayCHeap<char*, mtClassShared>* LambdaFormInvokers::_lambdaform_lines = nullptr;
|
||||
Array<u4>* LambdaFormInvokers::_static_archive_invokers = nullptr;
|
||||
Array<AOTCompressedPointers::narrowPtr>* LambdaFormInvokers::_static_archive_invokers = nullptr;
|
||||
static bool _stop_appending = false;
|
||||
|
||||
#define NUM_FILTER 4
|
||||
@ -252,7 +253,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
_static_archive_invokers = ArchiveBuilder::new_ro_array<u4>(count);
|
||||
_static_archive_invokers = ArchiveBuilder::new_ro_array<narrowPtr>(count);
|
||||
int index = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char* str = _lambdaform_lines->at(i);
|
||||
@ -261,7 +262,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
|
||||
Array<char>* line = ArchiveBuilder::new_ro_array<char>((int)str_len);
|
||||
strncpy(line->adr_at(0), str, str_len);
|
||||
|
||||
_static_archive_invokers->at_put(index, ArchiveBuilder::current()->any_to_offset_u4(line));
|
||||
_static_archive_invokers->at_put(index, AOTCompressedPointers::encode_not_null(line));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@ -274,8 +275,8 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
|
||||
void LambdaFormInvokers::read_static_archive_invokers() {
|
||||
if (_static_archive_invokers != nullptr) {
|
||||
for (int i = 0; i < _static_archive_invokers->length(); i++) {
|
||||
u4 offset = _static_archive_invokers->at(i);
|
||||
Array<char>* line = ArchiveUtils::offset_to_archived_address<Array<char>*>(offset);
|
||||
narrowPtr encoded = _static_archive_invokers->at(i);
|
||||
Array<char>* line = AOTCompressedPointers::decode_not_null<Array<char>*>(encoded);
|
||||
char* str = line->adr_at(0);
|
||||
append(str);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, 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
|
||||
@ -24,6 +24,8 @@
|
||||
|
||||
#ifndef SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
||||
#define SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
@ -35,10 +37,11 @@ class Array;
|
||||
class SerializeClosure;
|
||||
|
||||
class LambdaFormInvokers : public AllStatic {
|
||||
using narrowPtr = AOTCompressedPointers::narrowPtr;
|
||||
private:
|
||||
static GrowableArrayCHeap<char*, mtClassShared>* _lambdaform_lines;
|
||||
// For storing LF form lines (LF_RESOLVE only) in read only table.
|
||||
static Array<u4>* _static_archive_invokers;
|
||||
static Array<narrowPtr>* _static_archive_invokers;
|
||||
static void regenerate_class(char* name, ClassFileStream& st, TRAPS);
|
||||
public:
|
||||
static void append(char* line);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "cds/aotClassFilter.hpp"
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "cds/cdsProtectionDomain.hpp"
|
||||
@ -49,11 +50,11 @@ unsigned int LambdaProxyClassKey::hash() const {
|
||||
}
|
||||
|
||||
unsigned int RunTimeLambdaProxyClassKey::hash() const {
|
||||
return primitive_hash<u4>(_caller_ik) +
|
||||
primitive_hash<u4>(_invoked_name) +
|
||||
primitive_hash<u4>(_invoked_type) +
|
||||
primitive_hash<u4>(_method_type) +
|
||||
primitive_hash<u4>(_instantiated_method_type);
|
||||
return primitive_hash<u4>(cast_to_u4(_caller_ik)) +
|
||||
primitive_hash<u4>(cast_to_u4(_invoked_name)) +
|
||||
primitive_hash<u4>(cast_to_u4(_invoked_type)) +
|
||||
primitive_hash<u4>(cast_to_u4(_method_type)) +
|
||||
primitive_hash<u4>(cast_to_u4(_instantiated_method_type));
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -71,12 +72,12 @@ void LambdaProxyClassKey::print_on(outputStream* st) const {
|
||||
void RunTimeLambdaProxyClassKey::print_on(outputStream* st) const {
|
||||
ResourceMark rm;
|
||||
st->print_cr("LambdaProxyClassKey : " INTPTR_FORMAT " hash: %0x08x", p2i(this), hash());
|
||||
st->print_cr("_caller_ik : %d", _caller_ik);
|
||||
st->print_cr("_instantiated_method_type : %d", _instantiated_method_type);
|
||||
st->print_cr("_invoked_name : %d", _invoked_name);
|
||||
st->print_cr("_invoked_type : %d", _invoked_type);
|
||||
st->print_cr("_member_method : %d", _member_method);
|
||||
st->print_cr("_method_type : %d", _method_type);
|
||||
st->print_cr("_caller_ik : %d", cast_to_u4(_caller_ik));
|
||||
st->print_cr("_instantiated_method_type : %d", cast_to_u4(_instantiated_method_type));
|
||||
st->print_cr("_invoked_name : %d", cast_to_u4(_invoked_name));
|
||||
st->print_cr("_invoked_type : %d", cast_to_u4(_invoked_type));
|
||||
st->print_cr("_member_method : %d", cast_to_u4(_member_method));
|
||||
st->print_cr("_method_type : %d", cast_to_u4(_method_type));
|
||||
}
|
||||
|
||||
void RunTimeLambdaProxyClassInfo::print_on(outputStream* st) const {
|
||||
@ -418,8 +419,7 @@ public:
|
||||
(RunTimeLambdaProxyClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size);
|
||||
runtime_info->init(key, info);
|
||||
unsigned int hash = runtime_info->hash();
|
||||
u4 delta = _builder->any_to_offset_u4((void*)runtime_info);
|
||||
_writer->add(hash, delta);
|
||||
_writer->add(hash, AOTCompressedPointers::encode_not_null(runtime_info));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
@ -25,8 +25,9 @@
|
||||
#ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
|
||||
#define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "classfile/compactHashtable.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
@ -132,19 +133,20 @@ public:
|
||||
};
|
||||
|
||||
class RunTimeLambdaProxyClassKey {
|
||||
u4 _caller_ik;
|
||||
u4 _invoked_name;
|
||||
u4 _invoked_type;
|
||||
u4 _method_type;
|
||||
u4 _member_method;
|
||||
u4 _instantiated_method_type;
|
||||
using narrowPtr = AOTCompressedPointers::narrowPtr;
|
||||
narrowPtr _caller_ik;
|
||||
narrowPtr _invoked_name;
|
||||
narrowPtr _invoked_type;
|
||||
narrowPtr _method_type;
|
||||
narrowPtr _member_method;
|
||||
narrowPtr _instantiated_method_type;
|
||||
|
||||
RunTimeLambdaProxyClassKey(u4 caller_ik,
|
||||
u4 invoked_name,
|
||||
u4 invoked_type,
|
||||
u4 method_type,
|
||||
u4 member_method,
|
||||
u4 instantiated_method_type) :
|
||||
RunTimeLambdaProxyClassKey(narrowPtr caller_ik,
|
||||
narrowPtr invoked_name,
|
||||
narrowPtr invoked_type,
|
||||
narrowPtr method_type,
|
||||
narrowPtr member_method,
|
||||
narrowPtr instantiated_method_type) :
|
||||
_caller_ik(caller_ik),
|
||||
_invoked_name(invoked_name),
|
||||
_invoked_type(invoked_type),
|
||||
@ -154,15 +156,12 @@ class RunTimeLambdaProxyClassKey {
|
||||
|
||||
public:
|
||||
static RunTimeLambdaProxyClassKey init_for_dumptime(LambdaProxyClassKey& key) {
|
||||
assert(ArchiveBuilder::is_active(), "sanity");
|
||||
ArchiveBuilder* b = ArchiveBuilder::current();
|
||||
|
||||
u4 caller_ik = b->any_to_offset_u4(key.caller_ik());
|
||||
u4 invoked_name = b->any_to_offset_u4(key.invoked_name());
|
||||
u4 invoked_type = b->any_to_offset_u4(key.invoked_type());
|
||||
u4 method_type = b->any_to_offset_u4(key.method_type());
|
||||
u4 member_method = b->any_or_null_to_offset_u4(key.member_method()); // could be null
|
||||
u4 instantiated_method_type = b->any_to_offset_u4(key.instantiated_method_type());
|
||||
narrowPtr caller_ik = AOTCompressedPointers::encode_not_null(key.caller_ik());
|
||||
narrowPtr invoked_name = AOTCompressedPointers::encode_not_null(key.invoked_name());
|
||||
narrowPtr invoked_type = AOTCompressedPointers::encode_not_null(key.invoked_type());
|
||||
narrowPtr method_type = AOTCompressedPointers::encode_not_null(key.method_type());
|
||||
narrowPtr member_method = AOTCompressedPointers::encode(key.member_method()); // could be null
|
||||
narrowPtr instantiated_method_type = AOTCompressedPointers::encode_not_null(key.instantiated_method_type());
|
||||
|
||||
return RunTimeLambdaProxyClassKey(caller_ik, invoked_name, invoked_type, method_type,
|
||||
member_method, instantiated_method_type);
|
||||
@ -176,12 +175,12 @@ public:
|
||||
Symbol* instantiated_method_type) {
|
||||
// All parameters must be in shared space, or else you'd get an assert in
|
||||
// ArchiveUtils::to_offset().
|
||||
return RunTimeLambdaProxyClassKey(ArchiveUtils::archived_address_to_offset(caller_ik),
|
||||
ArchiveUtils::archived_address_to_offset(invoked_name),
|
||||
ArchiveUtils::archived_address_to_offset(invoked_type),
|
||||
ArchiveUtils::archived_address_to_offset(method_type),
|
||||
ArchiveUtils::archived_address_or_null_to_offset(member_method), // could be null
|
||||
ArchiveUtils::archived_address_to_offset(instantiated_method_type));
|
||||
return RunTimeLambdaProxyClassKey(AOTCompressedPointers::encode_address_in_cache(caller_ik),
|
||||
AOTCompressedPointers::encode_address_in_cache(invoked_name),
|
||||
AOTCompressedPointers::encode_address_in_cache(invoked_type),
|
||||
AOTCompressedPointers::encode_address_in_cache(method_type),
|
||||
AOTCompressedPointers::encode_address_in_cache_or_null(member_method), // could be null
|
||||
AOTCompressedPointers::encode_address_in_cache(instantiated_method_type));
|
||||
}
|
||||
|
||||
unsigned int hash() const;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
@ -22,15 +22,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/dumpTimeClassInfo.hpp"
|
||||
#include "cds/runTimeClassInfo.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
|
||||
void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
ArchiveBuilder* builder = ArchiveBuilder::current();
|
||||
InstanceKlass* k = info._klass;
|
||||
_klass_offset = builder->any_to_offset_u4(k);
|
||||
_klass = AOTCompressedPointers::encode_not_null(k);
|
||||
|
||||
if (!SystemDictionaryShared::is_builtin(k)) {
|
||||
CrcInfo* c = crc();
|
||||
@ -50,8 +50,8 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
RTVerifierConstraint* vf_constraints = verifier_constraints();
|
||||
char* flags = verifier_constraint_flags();
|
||||
for (i = 0; i < _num_verifier_constraints; i++) {
|
||||
vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name());
|
||||
vf_constraints[i]._from_name = builder->any_or_null_to_offset_u4(info._verifier_constraints->at(i).from_name());
|
||||
vf_constraints[i]._name = AOTCompressedPointers::encode_not_null(info._verifier_constraints->at(i).name());
|
||||
vf_constraints[i]._from_name = AOTCompressedPointers::encode(info._verifier_constraints->at(i).from_name());
|
||||
}
|
||||
for (i = 0; i < _num_verifier_constraints; i++) {
|
||||
flags[i] = info._verifier_constraint_flags->at(i);
|
||||
@ -61,14 +61,14 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
if (_num_loader_constraints > 0) {
|
||||
RTLoaderConstraint* ld_constraints = loader_constraints();
|
||||
for (i = 0; i < _num_loader_constraints; i++) {
|
||||
ld_constraints[i]._name = builder->any_to_offset_u4(info._loader_constraints->at(i).name());
|
||||
ld_constraints[i]._name = AOTCompressedPointers::encode_not_null(info._loader_constraints->at(i).name());
|
||||
ld_constraints[i]._loader_type1 = info._loader_constraints->at(i).loader_type1();
|
||||
ld_constraints[i]._loader_type2 = info._loader_constraints->at(i).loader_type2();
|
||||
}
|
||||
}
|
||||
|
||||
if (k->is_hidden() && info.nest_host() != nullptr) {
|
||||
_nest_host_offset = builder->any_to_offset_u4(info.nest_host());
|
||||
_nest_host = AOTCompressedPointers::encode_not_null(info.nest_host());
|
||||
}
|
||||
if (k->has_archived_enum_objs()) {
|
||||
int num = info.num_enum_klass_static_fields();
|
||||
@ -83,11 +83,12 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
|
||||
InstanceKlass* RunTimeClassInfo::klass() const {
|
||||
if (AOTMetaspace::in_aot_cache(this)) {
|
||||
// <this> is inside a mmaped CDS archive.
|
||||
return ArchiveUtils::offset_to_archived_address<InstanceKlass*>(_klass_offset);
|
||||
return AOTCompressedPointers::decode_not_null<InstanceKlass*>(_klass);
|
||||
} else {
|
||||
// <this> is a temporary copy of a RunTimeClassInfo that's being initialized
|
||||
// by the ArchiveBuilder.
|
||||
return ArchiveBuilder::current()->offset_to_buffered<InstanceKlass*>(_klass_offset);
|
||||
size_t byte_offset = AOTCompressedPointers::get_byte_offset(_klass);
|
||||
return ArchiveBuilder::current()->offset_to_buffered<InstanceKlass*>(byte_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_CDS_RUNTIMECLASSINFO_HPP
|
||||
#define SHARE_CDS_RUNTIMECLASSINFO_HPP
|
||||
|
||||
#include "cds/aotCompressedPointers.hpp"
|
||||
#include "cds/aotMetaspace.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveUtils.hpp"
|
||||
@ -41,8 +42,10 @@ class Method;
|
||||
class Symbol;
|
||||
|
||||
class RunTimeClassInfo {
|
||||
public:
|
||||
enum : char {
|
||||
using narrowPtr = AOTCompressedPointers::narrowPtr;
|
||||
|
||||
public:
|
||||
enum : char {
|
||||
FROM_FIELD_IS_PROTECTED = 1 << 0,
|
||||
FROM_IS_ARRAY = 1 << 1,
|
||||
FROM_IS_OBJECT = 1 << 2
|
||||
@ -56,19 +59,19 @@ class RunTimeClassInfo {
|
||||
// This is different than DumpTimeClassInfo::DTVerifierConstraint. We use
|
||||
// u4 instead of Symbol* to save space on 64-bit CPU.
|
||||
struct RTVerifierConstraint {
|
||||
u4 _name;
|
||||
u4 _from_name;
|
||||
Symbol* name() { return ArchiveUtils::offset_to_archived_address<Symbol*>(_name); }
|
||||
narrowPtr _name;
|
||||
narrowPtr _from_name;
|
||||
Symbol* name() { return AOTCompressedPointers::decode_not_null<Symbol*>(_name); }
|
||||
Symbol* from_name() {
|
||||
return (_from_name == 0) ? nullptr : ArchiveUtils::offset_to_archived_address<Symbol*>(_from_name);
|
||||
return AOTCompressedPointers::decode<Symbol*>(_from_name);
|
||||
}
|
||||
};
|
||||
|
||||
struct RTLoaderConstraint {
|
||||
u4 _name;
|
||||
narrowPtr _name;
|
||||
char _loader_type1;
|
||||
char _loader_type2;
|
||||
Symbol* constraint_name() { return ArchiveUtils::offset_to_archived_address<Symbol*>(_name); }
|
||||
Symbol* constraint_name() { return AOTCompressedPointers::decode_not_null<Symbol*>(_name); }
|
||||
};
|
||||
struct RTEnumKlassStaticFields {
|
||||
int _num;
|
||||
@ -76,8 +79,8 @@ class RunTimeClassInfo {
|
||||
};
|
||||
|
||||
private:
|
||||
u4 _klass_offset;
|
||||
u4 _nest_host_offset;
|
||||
narrowPtr _klass;
|
||||
narrowPtr _nest_host;
|
||||
int _num_verifier_constraints;
|
||||
int _num_loader_constraints;
|
||||
|
||||
@ -185,7 +188,7 @@ public:
|
||||
|
||||
InstanceKlass* nest_host() {
|
||||
assert(!ArchiveBuilder::is_active(), "not called when dumping archive");
|
||||
return ArchiveUtils::offset_to_archived_address_or_null<InstanceKlass*>(_nest_host_offset);
|
||||
return AOTCompressedPointers::decode<InstanceKlass*>(_nest_host); // may be null
|
||||
}
|
||||
|
||||
RTLoaderConstraint* loader_constraints() {
|
||||
|
||||
@ -213,7 +213,7 @@ ciField::ciField(fieldDescriptor *fd) :
|
||||
"bootstrap classes must not create & cache unshared fields");
|
||||
}
|
||||
|
||||
static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
|
||||
static bool trust_final_nonstatic_fields(ciInstanceKlass* holder) {
|
||||
if (holder == nullptr)
|
||||
return false;
|
||||
if (holder->trust_final_fields()) {
|
||||
@ -259,7 +259,7 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||
// An instance field can be constant if it's a final static field or if
|
||||
// it's a final non-static field of a trusted class (classes in
|
||||
// java.lang.invoke and sun.invoke packages and subpackages).
|
||||
_is_constant = is_stable_field || trust_final_non_static_fields(_holder);
|
||||
_is_constant = is_stable_field || trust_final_nonstatic_fields(_holder);
|
||||
}
|
||||
} else {
|
||||
// For CallSite objects treat the target field as a compile time constant.
|
||||
|
||||
@ -392,7 +392,7 @@ bool ciInstanceKlass::contains_field_offset(int offset) {
|
||||
return get_instanceKlass()->contains_field_offset(offset);
|
||||
}
|
||||
|
||||
ciField* ciInstanceKlass::get_non_static_field_by_offset(const int field_offset) {
|
||||
ciField* ciInstanceKlass::get_nonstatic_field_by_offset(const int field_offset) {
|
||||
for (int i = 0, len = nof_nonstatic_fields(); i < len; i++) {
|
||||
ciField* field = _nonstatic_fields->at(i);
|
||||
int field_off = field->offset_in_bytes();
|
||||
@ -406,7 +406,7 @@ ciField* ciInstanceKlass::get_non_static_field_by_offset(const int field_offset)
|
||||
// ciInstanceKlass::get_field_by_offset
|
||||
ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static) {
|
||||
if (!is_static) {
|
||||
return get_non_static_field_by_offset(field_offset);
|
||||
return get_nonstatic_field_by_offset(field_offset);
|
||||
}
|
||||
VM_ENTRY_MARK;
|
||||
InstanceKlass* k = get_instanceKlass();
|
||||
@ -437,7 +437,7 @@ ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature,
|
||||
// except this does not require allocating memory for a new ciField
|
||||
BasicType ciInstanceKlass::get_field_type_by_offset(const int field_offset, const bool is_static) {
|
||||
if (!is_static) {
|
||||
ciField* field = get_non_static_field_by_offset(field_offset);
|
||||
ciField* field = get_nonstatic_field_by_offset(field_offset);
|
||||
return field != nullptr ? field->layout_type() : T_ILLEGAL;
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ private:
|
||||
bool compute_injected_fields_helper();
|
||||
void compute_transitive_interfaces();
|
||||
|
||||
ciField* get_non_static_field_by_offset(int field_offset);
|
||||
ciField* get_nonstatic_field_by_offset(int field_offset);
|
||||
|
||||
protected:
|
||||
ciInstanceKlass(Klass* k);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user