mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8264806: Remove the experimental JIT compiler
Reviewed-by: iignatyev, erikj
This commit is contained in:
parent
7db9330c58
commit
4785e112ae
@ -52,94 +52,6 @@ $(eval $(call SetupJavaCompilation, BUILD_TOOLS_HOTSPOT, \
|
||||
TARGETS += $(BUILD_TOOLS_HOTSPOT)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Graal build tools
|
||||
ifeq ($(INCLUDE_GRAAL), true)
|
||||
VM_CI_SRC_DIR := $(TOPDIR)/src/jdk.internal.vm.ci/share/classes
|
||||
|
||||
SRC_DIR := $(TOPDIR)/src/jdk.internal.vm.compiler/share/classes
|
||||
|
||||
##############################################################################
|
||||
# Compile the annotation processors
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar, \
|
||||
DISABLED_WARNINGS := options, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_MATCH_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodeinfo.processor/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar, \
|
||||
DISABLED_WARNINGS := options, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_NODEINFO_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
|
||||
DISABLED_WARNINGS := options, \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
|
||||
, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_OPTIONS_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.processor/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \
|
||||
DISABLED_WARNINGS := options, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.compiler.processor/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \
|
||||
, \
|
||||
EXCLUDE_FILES := $(EXCLUDE_FILES), \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar, \
|
||||
DISABLED_WARNINGS := options, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR)
|
||||
|
||||
##############################################################################
|
||||
endif
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@ -662,18 +662,6 @@ $(eval $(call SetupTarget, test-image-libtest-jtreg-native, \
|
||||
DEPS := build-test-libtest-jtreg-native, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, build-test-hotspot-jtreg-graal, \
|
||||
MAKEFILE := test/JtregGraalUnit, \
|
||||
TARGET := build-test-hotspot-jtreg-graal, \
|
||||
DEPS := exploded-image, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, test-image-hotspot-jtreg-graal, \
|
||||
MAKEFILE := test/JtregGraalUnit, \
|
||||
TARGET := test-image-hotspot-jtreg-graal, \
|
||||
DEPS := build-test-hotspot-jtreg-graal, \
|
||||
))
|
||||
|
||||
ifneq ($(GTEST_FRAMEWORK_SRC), )
|
||||
$(eval $(call SetupTarget, test-image-hotspot-gtest, \
|
||||
MAKEFILE := hotspot/test/GtestImage, \
|
||||
@ -877,18 +865,6 @@ else
|
||||
# copied and processed.
|
||||
java.desktop-gensrc-src: java.base-gensrc java.base-copy
|
||||
|
||||
# The annotation processing for jdk.internal.vm.compiler
|
||||
# and jdk.internal.vm.compiler.management needs classes from the current JDK.
|
||||
jdk.internal.vm.compiler-gensrc-src: $(addsuffix -java, \
|
||||
$(call FindTransitiveDepsForModule, jdk.internal.vm.compiler))
|
||||
jdk.internal.vm.compiler.management-gensrc-src: $(addsuffix -java, \
|
||||
$(call FindTransitiveDepsForModule, jdk.internal.vm.compiler.management))
|
||||
|
||||
# For these modules, the gensrc step is generating a module-info.java.extra
|
||||
# file to be processed by the gensrc-moduleinfo target.
|
||||
jdk.internal.vm.compiler-gensrc-moduleinfo: jdk.internal.vm.compiler-gensrc-src
|
||||
jdk.internal.vm.compiler.management-gensrc-moduleinfo: jdk.internal.vm.compiler.management-gensrc-src
|
||||
|
||||
jdk.jdeps-gendata: java
|
||||
|
||||
# The ct.sym generation uses all the moduleinfos as input
|
||||
@ -1176,10 +1152,6 @@ else
|
||||
ifneq ($(GTEST_FRAMEWORK_SRC), )
|
||||
test-image: test-image-hotspot-gtest
|
||||
endif
|
||||
|
||||
ifeq ($(INCLUDE_GRAAL), true)
|
||||
test-image: test-image-hotspot-jtreg-graal
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_FAILURE_HANDLER), true)
|
||||
|
||||
@ -818,7 +818,6 @@ define SetupRunJtregTestBody
|
||||
endif
|
||||
|
||||
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_DIR=$(TEST_IMAGE_DIR)
|
||||
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_GRAAL_DIR=$(TEST_IMAGE_DIR)/hotspot/jtreg/graal
|
||||
|
||||
ifneq ($$(JTREG_FAILURE_HANDLER_OPTIONS), )
|
||||
$1_JTREG_LAUNCHER_OPTIONS += -Djava.library.path="$(JTREG_FAILURE_HANDLER_DIR)"
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
m4_define(jvm_features_valid, m4_normalize( \
|
||||
ifdef([custom_jvm_features_valid], custom_jvm_features_valid) \
|
||||
\
|
||||
cds compiler1 compiler2 dtrace epsilongc g1gc graal jfr jni-check \
|
||||
cds compiler1 compiler2 dtrace epsilongc g1gc jfr jni-check \
|
||||
jvmci jvmti link-time-opt management minimal nmt opt-size parallelgc \
|
||||
serialgc services shenandoahgc static-build vm-structs zero zgc \
|
||||
))
|
||||
@ -61,7 +61,6 @@ m4_define(jvm_feature_desc_compiler2, [enable hotspot compiler C2])
|
||||
m4_define(jvm_feature_desc_dtrace, [enable dtrace support])
|
||||
m4_define(jvm_feature_desc_epsilongc, [include the epsilon (no-op) garbage collector])
|
||||
m4_define(jvm_feature_desc_g1gc, [include the G1 garbage collector])
|
||||
m4_define(jvm_feature_desc_graal, [enable Graal (jdk.internal.vm.compiler)])
|
||||
m4_define(jvm_feature_desc_jfr, [enable JDK Flight Recorder (JFR)])
|
||||
m4_define(jvm_feature_desc_jni_check, [enable -Xcheck:jni support])
|
||||
m4_define(jvm_feature_desc_jvmci, [enable JVM Compiler Interface (JVMCI)])
|
||||
@ -266,25 +265,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_DTRACE],
|
||||
])
|
||||
])
|
||||
|
||||
###############################################################################
|
||||
# Check if the feature 'graal' is available on this platform.
|
||||
#
|
||||
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_GRAAL],
|
||||
[
|
||||
JVM_FEATURES_CHECK_AVAILABILITY(graal, [
|
||||
AC_MSG_CHECKING([if platform is supported by Graal])
|
||||
# Graal is only available where JVMCI is available since it requires JVMCI.
|
||||
if test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
elif test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no, $OPENJDK_TARGET_CPU])
|
||||
AVAILABLE=false
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
###############################################################################
|
||||
# Check if the feature 'jfr' is available on this platform.
|
||||
#
|
||||
@ -412,7 +392,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM],
|
||||
|
||||
JVM_FEATURES_CHECK_CDS
|
||||
JVM_FEATURES_CHECK_DTRACE
|
||||
JVM_FEATURES_CHECK_GRAAL
|
||||
JVM_FEATURES_CHECK_JFR
|
||||
JVM_FEATURES_CHECK_JVMCI
|
||||
JVM_FEATURES_CHECK_SHENANDOAHGC
|
||||
@ -446,17 +425,17 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
|
||||
JVM_FEATURES_VARIANT_UNAVAILABLE="cds minimal zero"
|
||||
elif test "x$variant" = "xzero"; then
|
||||
JVM_FEATURES_VARIANT_UNAVAILABLE="cds compiler1 compiler2 \
|
||||
graal jvmci minimal zgc"
|
||||
jvmci minimal zgc"
|
||||
else
|
||||
JVM_FEATURES_VARIANT_UNAVAILABLE="minimal zero"
|
||||
fi
|
||||
|
||||
# Check which features should be off by default for this JVM variant.
|
||||
if test "x$variant" = "xclient"; then
|
||||
JVM_FEATURES_VARIANT_FILTER="compiler2 graal jvmci link-time-opt opt-size"
|
||||
JVM_FEATURES_VARIANT_FILTER="compiler2 jvmci link-time-opt opt-size"
|
||||
elif test "x$variant" = "xminimal"; then
|
||||
JVM_FEATURES_VARIANT_FILTER="cds compiler2 dtrace epsilongc g1gc \
|
||||
graal jfr jni-check jvmci jvmti management nmt parallelgc services \
|
||||
jfr jni-check jvmci jvmti management nmt parallelgc services \
|
||||
shenandoahgc vm-structs zgc"
|
||||
if test "x$OPENJDK_TARGET_CPU" = xarm ; then
|
||||
JVM_FEATURES_VARIANT_FILTER="$JVM_FEATURES_VARIANT_FILTER opt-size"
|
||||
@ -466,7 +445,7 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
|
||||
link-time-opt"
|
||||
fi
|
||||
elif test "x$variant" = "xcore"; then
|
||||
JVM_FEATURES_VARIANT_FILTER="compiler1 compiler2 graal jvmci \
|
||||
JVM_FEATURES_VARIANT_FILTER="compiler1 compiler2 jvmci \
|
||||
link-time-opt opt-size"
|
||||
elif test "x$variant" = "xzero"; then
|
||||
JVM_FEATURES_VARIANT_FILTER="jfr link-time-opt opt-size"
|
||||
@ -542,11 +521,6 @@ AC_DEFUN([JVM_FEATURES_VERIFY],
|
||||
[
|
||||
variant=$1
|
||||
|
||||
# Verify that dependencies are met for inter-feature relations.
|
||||
if JVM_FEATURES_IS_ACTIVE(graal) && ! JVM_FEATURES_IS_ACTIVE(jvmci); then
|
||||
AC_MSG_ERROR([Specified JVM feature 'graal' requires feature 'jvmci' for variant '$variant'])
|
||||
fi
|
||||
|
||||
if JVM_FEATURES_IS_ACTIVE(jvmci) && ! (JVM_FEATURES_IS_ACTIVE(compiler1) || \
|
||||
JVM_FEATURES_IS_ACTIVE(compiler2)); then
|
||||
AC_MSG_ERROR([Specified JVM feature 'jvmci' requires feature 'compiler2' or 'compiler1' for variant '$variant'])
|
||||
@ -565,9 +539,6 @@ AC_DEFUN([JVM_FEATURES_VERIFY],
|
||||
if ! JVM_FEATURES_IS_ACTIVE(cds); then
|
||||
ENABLE_CDS="false"
|
||||
fi
|
||||
if ! JVM_FEATURES_IS_ACTIVE(graal); then
|
||||
INCLUDE_GRAAL="false"
|
||||
fi
|
||||
if ! JVM_FEATURES_IS_ACTIVE(jvmci); then
|
||||
INCLUDE_JVMCI="false"
|
||||
fi
|
||||
@ -593,7 +564,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP],
|
||||
# and disable them in JVM_FEATURES_VERIFY if a variant is found that are
|
||||
# missing any of them.
|
||||
ENABLE_CDS="true"
|
||||
INCLUDE_GRAAL="true"
|
||||
INCLUDE_JVMCI="true"
|
||||
|
||||
for variant in $JVM_VARIANTS; do
|
||||
@ -630,7 +600,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP],
|
||||
AC_SUBST(JVM_FEATURES_zero)
|
||||
AC_SUBST(JVM_FEATURES_custom)
|
||||
|
||||
AC_SUBST(INCLUDE_GRAAL)
|
||||
AC_SUBST(INCLUDE_JVMCI)
|
||||
|
||||
])
|
||||
|
||||
@ -23,38 +23,6 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Check for graalunit libs, needed for running graalunit tests.
|
||||
#
|
||||
AC_DEFUN_ONCE([LIB_TESTS_SETUP_GRAALUNIT],
|
||||
[
|
||||
AC_ARG_WITH(graalunit-lib, [AS_HELP_STRING([--with-graalunit-lib],
|
||||
[specify location of 3rd party libraries used by Graal unit tests])])
|
||||
|
||||
GRAALUNIT_LIB=
|
||||
if test "x${with_graalunit_lib}" != x; then
|
||||
AC_MSG_CHECKING([for graalunit libs])
|
||||
if test "x${with_graalunit_lib}" = xno; then
|
||||
AC_MSG_RESULT([disabled, graalunit tests can not be run])
|
||||
elif test "x${with_graalunit_lib}" = xyes; then
|
||||
AC_MSG_RESULT([not specified])
|
||||
AC_MSG_ERROR([You must specify the path to 3rd party libraries used by Graal unit tests])
|
||||
else
|
||||
GRAALUNIT_LIB="${with_graalunit_lib}"
|
||||
if test ! -d "${GRAALUNIT_LIB}"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Could not find graalunit 3rd party libraries as specified. (${with_graalunit_lib})])
|
||||
else
|
||||
AC_MSG_RESULT([$GRAALUNIT_LIB])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
UTIL_FIXUP_PATH([GRAALUNIT_LIB])
|
||||
AC_SUBST(GRAALUNIT_LIB)
|
||||
])
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Setup and check for gtest framework source files
|
||||
|
||||
@ -103,7 +103,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
LIB_SETUP_LIBFFI
|
||||
LIB_SETUP_BUNDLED_LIBS
|
||||
LIB_SETUP_MISC_LIBS
|
||||
LIB_TESTS_SETUP_GRAALUNIT
|
||||
LIB_TESTS_SETUP_GTEST
|
||||
|
||||
BASIC_JDKLIB_LIBS=""
|
||||
|
||||
@ -392,7 +392,6 @@ LIBFFI_LIBS:=@LIBFFI_LIBS@
|
||||
LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
|
||||
ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@
|
||||
LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@
|
||||
GRAALUNIT_LIB := @GRAALUNIT_LIB@
|
||||
FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@
|
||||
|
||||
STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@
|
||||
@ -850,7 +849,6 @@ PNG_CFLAGS:=@PNG_CFLAGS@
|
||||
#
|
||||
|
||||
INCLUDE_SA=@INCLUDE_SA@
|
||||
INCLUDE_GRAAL=@INCLUDE_GRAAL@
|
||||
INCLUDE_JVMCI=@INCLUDE_JVMCI@
|
||||
|
||||
OS_VERSION_MAJOR:=@OS_VERSION_MAJOR@
|
||||
|
||||
@ -64,11 +64,9 @@ ifeq ($(INCLUDE_JVMCI), false)
|
||||
MODULES_FILTER += jdk.internal.vm.ci
|
||||
endif
|
||||
|
||||
# Filter out Graal specific modules if Graal is disabled
|
||||
ifeq ($(INCLUDE_GRAAL), false)
|
||||
MODULES_FILTER += jdk.internal.vm.compiler
|
||||
MODULES_FILTER += jdk.internal.vm.compiler.management
|
||||
endif
|
||||
# Filter out Graal specific modules
|
||||
MODULES_FILTER += jdk.internal.vm.compiler
|
||||
MODULES_FILTER += jdk.internal.vm.compiler.management
|
||||
|
||||
# jpackage is only on windows, macosx, and linux
|
||||
ifeq ($(call isTargetOs, windows macosx linux), false)
|
||||
|
||||
@ -46,6 +46,4 @@ LANGTOOLS_MODULES= \
|
||||
HOTSPOT_MODULES= \
|
||||
jdk.hotspot.agent \
|
||||
jdk.internal.vm.ci \
|
||||
jdk.internal.vm.compiler \
|
||||
jdk.internal.vm.compiler.management \
|
||||
#
|
||||
|
||||
@ -251,7 +251,6 @@ var getJibProfilesCommon = function (input, data) {
|
||||
configure_args: concat("--enable-jtreg-failure-handler",
|
||||
"--with-exclude-translations=de,es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK",
|
||||
"--disable-manpages",
|
||||
"--disable-jvm-feature-graal",
|
||||
"--disable-jvm-feature-shenandoahgc",
|
||||
versionArgs(input, common))
|
||||
};
|
||||
|
||||
@ -61,8 +61,6 @@ BOOT_MODULES= \
|
||||
# should carefully be considered if it should be upgradeable or not.
|
||||
UPGRADEABLE_PLATFORM_MODULES= \
|
||||
java.compiler \
|
||||
jdk.internal.vm.compiler \
|
||||
jdk.internal.vm.compiler.management \
|
||||
#
|
||||
|
||||
PLATFORM_MODULES= \
|
||||
|
||||
@ -113,7 +113,6 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
-hidePath .jcheck \
|
||||
-hidePath jdk.hotspot.agent \
|
||||
-hidePath jdk.internal.vm.ci \
|
||||
-hidePath jdk.internal.vm.compiler \
|
||||
-hidePath jdk.jfr \
|
||||
-compiler VC10 \
|
||||
-jdkTargetRoot $(call FixPath, $(JDK_OUTPUTDIR)) \
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)
|
||||
SRC_DIR := $(TOPDIR)/src/$(MODULE)/share/classes
|
||||
|
||||
################################################################################
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
org.graalvm.compiler.hotspot.management \
|
||||
#
|
||||
|
||||
PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS))
|
||||
|
||||
PROC_SRCS := $(filter %.java, $(call FindFiles, $(PROC_SRC_DIRS)))
|
||||
|
||||
ALL_SRC_DIRS := $(SRC_DIR) $(wildcard $(SRC_DIR)/*/src)
|
||||
SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS))
|
||||
|
||||
PROCESSOR_JARS := \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar \
|
||||
#
|
||||
PROCESSOR_PATH := $(call PathList, $(PROCESSOR_JARS))
|
||||
|
||||
$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS)
|
||||
$(call MakeDir, $(@D))
|
||||
$(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files))
|
||||
$(JAVA) $(NEW_JAVAC) \
|
||||
-XDignore.symbol.file \
|
||||
--upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none \
|
||||
-sourcepath $(SOURCEPATH) \
|
||||
-implicit:none \
|
||||
-proc:only \
|
||||
-processorpath $(PROCESSOR_PATH) \
|
||||
-d $(GENSRC_DIR) \
|
||||
-s $(GENSRC_DIR) \
|
||||
@$(@D)/_gensrc_proc_files
|
||||
$(TOUCH) $@
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/_gensrc_proc_done
|
||||
|
||||
################################################################################
|
||||
|
||||
$(GENSRC_DIR)/module-info.java.extra: $(GENSRC_DIR)/_gensrc_proc_done
|
||||
$(ECHO) "" > $@;
|
||||
($(CD) $(GENSRC_DIR)/META-INF/providers && \
|
||||
p=""; \
|
||||
impl=""; \
|
||||
for i in $$($(AWK) '$$0=FILENAME" "$$0' * | $(SORT) -k 2 | $(SED) 's/ .*//'); do \
|
||||
c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
|
||||
if test x$$p != x$$c; then \
|
||||
if test x$$p != x; then \
|
||||
$(ECHO) " ;" >> $@; \
|
||||
fi; \
|
||||
$(ECHO) "provides $$c with" >> $@; \
|
||||
p=$$c; \
|
||||
impl=""; \
|
||||
fi; \
|
||||
if test x$$impl != x; then \
|
||||
$(ECHO) " , $$i" >> $@; \
|
||||
else \
|
||||
$(ECHO) " $$i" >> $@; \
|
||||
fi; \
|
||||
impl=$$i; \
|
||||
done); \
|
||||
$(ECHO) " ;" >> $@;
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/module-info.java.extra
|
||||
@ -1,150 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)
|
||||
SRC_DIR := $(TOPDIR)/src/$(MODULE)/share/classes
|
||||
|
||||
################################################################################
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
org.graalvm.compiler.asm.amd64 \
|
||||
org.graalvm.compiler.code \
|
||||
org.graalvm.compiler.core \
|
||||
org.graalvm.compiler.core.aarch64 \
|
||||
org.graalvm.compiler.core.amd64 \
|
||||
org.graalvm.compiler.core.common \
|
||||
org.graalvm.compiler.debug \
|
||||
org.graalvm.compiler.hotspot \
|
||||
org.graalvm.compiler.hotspot.aarch64 \
|
||||
org.graalvm.compiler.hotspot.amd64 \
|
||||
org.graalvm.compiler.graph \
|
||||
org.graalvm.compiler.java \
|
||||
org.graalvm.compiler.lir \
|
||||
org.graalvm.compiler.lir.amd64 \
|
||||
org.graalvm.compiler.loop \
|
||||
org.graalvm.compiler.loop.phases \
|
||||
org.graalvm.compiler.nodes \
|
||||
org.graalvm.compiler.replacements \
|
||||
org.graalvm.compiler.replacements.aarch64 \
|
||||
org.graalvm.compiler.replacements.amd64 \
|
||||
org.graalvm.compiler.phases \
|
||||
org.graalvm.compiler.phases.common \
|
||||
org.graalvm.compiler.printer \
|
||||
org.graalvm.compiler.virtual \
|
||||
#
|
||||
|
||||
PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS))
|
||||
|
||||
PROC_SRCS := $(filter %.java, $(call FindFiles, $(PROC_SRC_DIRS)))
|
||||
|
||||
ALL_SRC_DIRS := $(SRC_DIR) $(wildcard $(SRC_DIR)/*/src)
|
||||
SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS))
|
||||
|
||||
PROCESSOR_JARS := \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor.jar \
|
||||
#
|
||||
PROCESSOR_PATH := $(call PathList, $(PROCESSOR_JARS))
|
||||
|
||||
ADD_EXPORTS := \
|
||||
--add-modules jdk.internal.vm.ci \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code.stack=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.events=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspotvmconfig=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.inittimer=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.services=jdk.internal.vm.compiler \
|
||||
#
|
||||
|
||||
$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS)
|
||||
$(call MakeDir, $(@D))
|
||||
$(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files))
|
||||
$(JAVA) $(NEW_JAVAC) \
|
||||
-XDignore.symbol.file \
|
||||
--upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none \
|
||||
$(ADD_EXPORTS) \
|
||||
-sourcepath $(SOURCEPATH) \
|
||||
-implicit:none \
|
||||
-proc:only \
|
||||
-processorpath $(PROCESSOR_PATH) \
|
||||
-d $(GENSRC_DIR) \
|
||||
-s $(GENSRC_DIR) \
|
||||
@$(@D)/_gensrc_proc_files
|
||||
$(TOUCH) $@
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/_gensrc_proc_done
|
||||
|
||||
################################################################################
|
||||
|
||||
$(GENSRC_DIR)/module-info.java.extra: $(GENSRC_DIR)/_gensrc_proc_done
|
||||
$(ECHO) "" > $@;
|
||||
($(CD) $(GENSRC_DIR)/META-INF/providers && \
|
||||
p=""; \
|
||||
impl=""; \
|
||||
for i in $$($(GREP) '^' * | $(SORT) -t ':' -k 2 | $(SED) 's/:.*//'); do \
|
||||
c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
|
||||
if test x$$p != x$$c; then \
|
||||
if test x$$p != x; then \
|
||||
$(ECHO) " ;" >> $@; \
|
||||
fi; \
|
||||
$(ECHO) "provides $$c with" >> $@; \
|
||||
p=$$c; \
|
||||
impl=""; \
|
||||
fi; \
|
||||
if test x$$impl != x; then \
|
||||
$(ECHO) " , $$i" >> $@; \
|
||||
else \
|
||||
$(ECHO) " $$i" >> $@; \
|
||||
fi; \
|
||||
impl=$$i; \
|
||||
done); \
|
||||
$(ECHO) " ;" >> $@; \
|
||||
$(ECHO) "uses org.graalvm.compiler.options.OptionDescriptors;" >> $@; \
|
||||
$(ECHO) "provides org.graalvm.compiler.options.OptionDescriptors with" >> $@; \
|
||||
impl=""; \
|
||||
for i in $$($(FIND) $(GENSRC_DIR) -name '*_OptionDescriptors.java' | $(SORT)); do \
|
||||
c=$$($(ECHO) $$i | $(SED) 's:.*/jdk\.internal\.vm\.compiler/\(.*\)\.java:\1:' | $(TR) '/' '.'); \
|
||||
if test x$$impl != x; then \
|
||||
$(ECHO) " , $$c" >> $@; \
|
||||
else \
|
||||
$(ECHO) " $$c" >> $@; \
|
||||
fi; \
|
||||
impl=$$c; \
|
||||
done; \
|
||||
$(ECHO) " ;" >> $@;
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/module-info.java.extra
|
||||
@ -1,87 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2020, 2021, 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. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
JAVAC_FLAGS += -parameters -XDstringConcat=inline \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.aarch64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.amd64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code.site=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.code.stack=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.common=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler \
|
||||
--add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler \
|
||||
#
|
||||
|
||||
EXCLUDES += \
|
||||
jdk.internal.vm.compiler.collections.test \
|
||||
org.graalvm.compiler.api.directives.test \
|
||||
org.graalvm.compiler.api.test \
|
||||
org.graalvm.compiler.asm.aarch64.test \
|
||||
org.graalvm.compiler.asm.amd64.test \
|
||||
org.graalvm.compiler.asm.test \
|
||||
org.graalvm.compiler.core.aarch64.test \
|
||||
org.graalvm.compiler.core.amd64.test \
|
||||
org.graalvm.compiler.core.jdk9.test \
|
||||
org.graalvm.compiler.core.match.processor \
|
||||
org.graalvm.compiler.core.test \
|
||||
org.graalvm.compiler.debug.test \
|
||||
org.graalvm.compiler.graph.test \
|
||||
org.graalvm.compiler.hotspot.aarch64.test \
|
||||
org.graalvm.compiler.hotspot.amd64.test \
|
||||
org.graalvm.compiler.hotspot.jdk15.test \
|
||||
org.graalvm.compiler.hotspot.jdk9.test \
|
||||
org.graalvm.compiler.hotspot.lir.test \
|
||||
org.graalvm.compiler.hotspot.test \
|
||||
org.graalvm.compiler.jtt \
|
||||
org.graalvm.compiler.lir.jtt \
|
||||
org.graalvm.compiler.lir.test \
|
||||
org.graalvm.compiler.loop.test \
|
||||
org.graalvm.compiler.microbenchmarks \
|
||||
org.graalvm.compiler.nodeinfo.processor \
|
||||
org.graalvm.compiler.nodes.test \
|
||||
org.graalvm.compiler.options.processor \
|
||||
org.graalvm.compiler.options.test \
|
||||
org.graalvm.compiler.phases.common.test \
|
||||
org.graalvm.compiler.processor \
|
||||
org.graalvm.compiler.replacements.jdk10.test \
|
||||
org.graalvm.compiler.replacements.jdk12.test \
|
||||
org.graalvm.compiler.replacements.jdk9.test \
|
||||
org.graalvm.compiler.replacements.processor \
|
||||
org.graalvm.compiler.replacements.test \
|
||||
org.graalvm.compiler.serviceprovider.processor \
|
||||
org.graalvm.compiler.test \
|
||||
org.graalvm.compiler.virtual.bench \
|
||||
org.graalvm.micro.benchmarks \
|
||||
org.graalvm.util.test \
|
||||
#
|
||||
|
||||
## WORKAROUND jdk.internal.vm.compiler source structure issue
|
||||
VM_COMPILER_MODULESOURCEPATH := $(MODULESOURCEPATH) \
|
||||
$(subst /$(MODULE)/,/*/, $(filter-out %processor/src %test/src %jtt/src %bench/src %microbenchmarks/src, \
|
||||
$(wildcard $(TOPDIR)/src/$(MODULE)/share/classes/*/src)))
|
||||
MODULESOURCEPATH := $(call PathList, $(VM_COMPILER_MODULESOURCEPATH))
|
||||
@ -1,188 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# This file builds Graal component of the JTReg tests for Hotspot.
|
||||
# It also covers the test-image part, where the built files are copied to the
|
||||
# test image.
|
||||
################################################################################
|
||||
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include JavaCompilation.gmk
|
||||
|
||||
TARGETS_BUILD :=
|
||||
TARGETS_IMAGE :=
|
||||
TARGETS_EXTRA_LIB :=
|
||||
|
||||
ifeq ($(INCLUDE_GRAAL), true)
|
||||
ifneq ($(GRAALUNIT_LIB), )
|
||||
|
||||
SRC_DIR := $(TOPDIR)/src/jdk.internal.vm.compiler/share/classes
|
||||
TEST_DIR := $(TOPDIR)/test/hotspot/jtreg/compiler/graalunit
|
||||
COMPILE_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/test/graalunit
|
||||
LIB_OUTPUTDIR := $(TEST_IMAGE_DIR)/hotspot/jtreg/graal
|
||||
|
||||
# This evaluation is expensive and should only be done if this target was
|
||||
# explicitly called.
|
||||
ifneq ($(filter build-test-hotspot-jtreg-graal, $(MAKECMDGOALS)), )
|
||||
|
||||
TEST_COMPILE_CP := \
|
||||
$(JDK_OUTPUTDIR)/modules/jdk.internal.vm.compiler \
|
||||
$(JDK_OUTPUTDIR)/modules/jdk.internal.vm.ci \
|
||||
$(LIB_OUTPUTDIR)/junit-4.12.jar \
|
||||
$(LIB_OUTPUTDIR)/asm-5.0.4.jar \
|
||||
$(LIB_OUTPUTDIR)/asm-tree-5.0.4.jar \
|
||||
$(LIB_OUTPUTDIR)/java-allocation-instrumenter.jar \
|
||||
$(LIB_OUTPUTDIR)/hamcrest-core-1.3.jar
|
||||
|
||||
TEST_JAVAC_FLAGS := \
|
||||
-processorpath $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar \
|
||||
--add-exports jdk.unsupported/sun.misc=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.module=ALL-UNNAMED \
|
||||
-Xprefer:newer \
|
||||
#
|
||||
|
||||
### Copy 3rd party libs
|
||||
$(eval $(call SetupCopyFiles, COPY_GRAALUNIT_LIBS, \
|
||||
FILES := $(wildcard $(GRAALUNIT_LIB)/*.jar), \
|
||||
DEST := $(LIB_OUTPUTDIR), \
|
||||
))
|
||||
|
||||
TARGETS_EXTRA_LIB += $(COPY_GRAALUNIT_LIBS)
|
||||
|
||||
### Compile graalunit tests
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_TESTS, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
|
||||
SRC := \
|
||||
$(SRC_DIR)/jdk.internal.vm.compiler.collections.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.directives.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm.aarch64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm.amd64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.asm.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.aarch64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.amd64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.jdk9.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.core.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.debug.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.graph.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.aarch64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.amd64.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.jdk15.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.jdk9.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.lir.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.hotspot.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.jtt/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.lir.jtt/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.lir.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.loop.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.nodes.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.options.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.phases.common.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.jdk10.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.jdk12.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.jdk9.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.test/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.test/src \
|
||||
$(SRC_DIR)/org.graalvm.util.test/src \
|
||||
, \
|
||||
EXCLUDE_FILES := org/graalvm/compiler/core/test/VerifyDebugUsageTest.java, \
|
||||
BIN := $(COMPILE_OUTPUTDIR)/jdk.vm.compiler.tests, \
|
||||
CLASSPATH := $(TEST_COMPILE_CP), \
|
||||
DISABLED_WARNINGS := processing, \
|
||||
JAVAC_FLAGS := $(TEST_JAVAC_FLAGS), \
|
||||
COPY := .input, \
|
||||
))
|
||||
|
||||
TARGETS_BUILD += $(BUILD_VM_COMPILER_TESTS)
|
||||
|
||||
### Compile graalunit tests which require -XDstringConcat=inline
|
||||
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_TESTS_SET2, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
|
||||
DEPENDS := $(BUILD_VM_COMPILER_TESTS), \
|
||||
SRC := $(SRC_DIR)/org.graalvm.compiler.core.test/src, \
|
||||
INCLUDE_FILES := org/graalvm/compiler/core/test/VerifyDebugUsageTest.java, \
|
||||
BIN := $(COMPILE_OUTPUTDIR)/jdk.vm.compiler.tests, \
|
||||
CLASSPATH := \
|
||||
$(TEST_COMPILE_CP) \
|
||||
$(COMPILE_OUTPUTDIR)/jdk.vm.compiler.tests, \
|
||||
DISABLED_WARNINGS := processing, \
|
||||
JAVAC_FLAGS := $(TEST_JAVAC_FLAGS) -XDstringConcat=inline, \
|
||||
))
|
||||
|
||||
TARGETS_BUILD += $(BUILD_VM_COMPILER_TESTS_SET2)
|
||||
|
||||
### Generate jdk.vm.compiler.tests.jar
|
||||
$(eval $(call SetupJarArchive, BUILD_VM_COMPILER_TESTS_JAR, \
|
||||
DEPENDENCIES := $(BUILD_VM_COMPILER_TESTS) $(BUILD_VM_COMPILER_TESTS_SET2), \
|
||||
SRCS := $(COMPILE_OUTPUTDIR)/jdk.vm.compiler.tests, \
|
||||
SUFFIXES:=.class .input, \
|
||||
JAR := $(COMPILE_OUTPUTDIR)/jdk.vm.compiler.tests.jar, \
|
||||
))
|
||||
|
||||
TARGETS_BUILD += $(BUILD_VM_COMPILER_TESTS_JAR)
|
||||
|
||||
### Compile and build mxtool
|
||||
$(eval $(call SetupJavaCompilation, BUILD_MXTOOL, \
|
||||
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
|
||||
SRC := $(TEST_DIR)/com.oracle.mxtool.junit, \
|
||||
BIN := $(COMPILE_OUTPUTDIR)/com.oracle.mxtool.junit, \
|
||||
JAR := $(COMPILE_OUTPUTDIR)/com.oracle.mxtool.junit.jar, \
|
||||
DISABLED_WARNINGS := processing, \
|
||||
CLASSPATH := $(LIB_OUTPUTDIR)/junit-4.12.jar, \
|
||||
))
|
||||
|
||||
TARGETS_BUILD += $(BUILD_MXTOOL)
|
||||
|
||||
$(TARGETS_BUILD): $(TARGETS_EXTRA_LIB)
|
||||
|
||||
endif # build-test-hotspot-jtreg-graal
|
||||
|
||||
################################################################################
|
||||
# Targets for building test-image.
|
||||
################################################################################
|
||||
|
||||
# Copy to hotspot jtreg test image
|
||||
$(eval $(call SetupCopyFiles, COPY_HOTSPOT_JTREG_GRAAL, \
|
||||
SRC := $(COMPILE_OUTPUTDIR), \
|
||||
DEST := $(LIB_OUTPUTDIR), \
|
||||
FILES := jdk.vm.compiler.tests.jar com.oracle.mxtool.junit.jar, \
|
||||
))
|
||||
|
||||
TARGETS_IMAGE += $(COPY_HOTSPOT_JTREG_GRAAL)
|
||||
endif
|
||||
endif
|
||||
|
||||
build-test-hotspot-jtreg-graal: $(TARGETS_BUILD)
|
||||
test-image-hotspot-jtreg-graal: $(TARGETS_IMAGE)
|
||||
|
||||
all: build-test-hotspot-jtreg-graal
|
||||
test-image: test-image-hotspot-jtreg-graal
|
||||
|
||||
.PHONY: default all build-test-hotspot-jtreg-graal test-image-hotspot-jtreg-graal test-image
|
||||
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.hotspot.management;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalManagementRegistration;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalRuntime;
|
||||
import org.graalvm.compiler.serviceprovider.ServiceProvider;
|
||||
|
||||
/**
|
||||
* Dynamically registers an MBean with the {@link ManagementFactory#getPlatformMBeanServer()}.
|
||||
*
|
||||
* Polling for an active platform MBean server is done by calling
|
||||
* {@link MBeanServerFactory#findMBeanServer(String)} with an argument value of {@code null}. Once
|
||||
* this returns an non-empty list, {@link ManagementFactory#getPlatformMBeanServer()} can be called
|
||||
* to obtain a reference to the platform MBean server instance.
|
||||
*/
|
||||
@ServiceProvider(HotSpotGraalManagementRegistration.class)
|
||||
public final class HotSpotGraalManagement implements HotSpotGraalManagementRegistration {
|
||||
|
||||
private HotSpotGraalRuntimeMBean bean;
|
||||
private volatile boolean needsRegistration = true;
|
||||
HotSpotGraalManagement nextDeferred;
|
||||
|
||||
@Override
|
||||
public void initialize(HotSpotGraalRuntime runtime, GraalHotSpotVMConfig config) {
|
||||
if (bean == null) {
|
||||
if (runtime.getManagement() != this) {
|
||||
throw new IllegalArgumentException("Cannot initialize a second management object for runtime " + runtime.getName());
|
||||
}
|
||||
try {
|
||||
String name = runtime.getName().replace(':', '_');
|
||||
ObjectName objectName = new ObjectName("org.graalvm.compiler.hotspot:type=" + name);
|
||||
bean = new HotSpotGraalRuntimeMBean(objectName, runtime);
|
||||
registration.add(this);
|
||||
} catch (MalformedObjectNameException err) {
|
||||
err.printStackTrace(TTY.out);
|
||||
}
|
||||
} else if (bean.getRuntime() != runtime) {
|
||||
throw new IllegalArgumentException("Cannot change the runtime a management interface is associated with");
|
||||
}
|
||||
}
|
||||
|
||||
static final class RegistrationThread extends Thread {
|
||||
|
||||
private MBeanServer platformMBeanServer;
|
||||
private HotSpotGraalManagement deferred;
|
||||
|
||||
RegistrationThread() {
|
||||
super("HotSpotGraalManagement Bean Registration");
|
||||
this.setPriority(Thread.MIN_PRIORITY);
|
||||
this.setDaemon(true);
|
||||
this.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for active MBean server every 2 seconds.
|
||||
*/
|
||||
private static final int POLL_INTERVAL_MS = 2000;
|
||||
|
||||
/**
|
||||
* Adds a {@link HotSpotGraalManagement} to register with an active MBean server when one
|
||||
* becomes available.
|
||||
*/
|
||||
synchronized void add(HotSpotGraalManagement e) {
|
||||
if (deferred != null) {
|
||||
e.nextDeferred = deferred;
|
||||
}
|
||||
deferred = e;
|
||||
|
||||
// Notify the registration thread that there is now
|
||||
// a deferred registration to process
|
||||
notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and clears any deferred registrations.
|
||||
*/
|
||||
private void process() {
|
||||
for (HotSpotGraalManagement m = deferred; m != null; m = m.nextDeferred) {
|
||||
HotSpotGraalRuntimeMBean bean = m.bean;
|
||||
if (m.needsRegistration && bean != null) {
|
||||
try {
|
||||
platformMBeanServer.registerMBean(bean, bean.getObjectName());
|
||||
} catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
|
||||
e.printStackTrace(TTY.out);
|
||||
// Registration failed - don't try again
|
||||
m.bean = null;
|
||||
}
|
||||
m.needsRegistration = false;
|
||||
}
|
||||
}
|
||||
deferred = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
// Wait until there are deferred registrations to process
|
||||
while (deferred == null) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
poll();
|
||||
Thread.sleep(POLL_INTERVAL_MS);
|
||||
} catch (InterruptedException e) {
|
||||
// Be verbose about unexpected interruption and then continue
|
||||
e.printStackTrace(TTY.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for active MBean server and if available, processes deferred registrations.
|
||||
*/
|
||||
synchronized void poll() {
|
||||
if (platformMBeanServer == null) {
|
||||
try {
|
||||
ArrayList<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
|
||||
if (!servers.isEmpty()) {
|
||||
platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
process();
|
||||
}
|
||||
} catch (SecurityException | UnsatisfiedLinkError | NoClassDefFoundError | UnsupportedOperationException e) {
|
||||
// Without permission to find or create the MBeanServer,
|
||||
// we cannot process any Graal mbeans.
|
||||
// Various other errors can occur in the ManagementFactory (JDK-8076557)
|
||||
deferred = null;
|
||||
}
|
||||
} else {
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final RegistrationThread registration = new RegistrationThread();
|
||||
|
||||
@Override
|
||||
public ObjectName poll(boolean sync) {
|
||||
if (sync) {
|
||||
registration.poll();
|
||||
}
|
||||
if (bean == null || needsRegistration) {
|
||||
// initialize() has not been called, it failed or registration failed
|
||||
return null;
|
||||
}
|
||||
return bean.getObjectName();
|
||||
}
|
||||
}
|
||||
@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.hotspot.management;
|
||||
|
||||
import org.graalvm.compiler.phases.common.jmx.HotSpotMBeanOperationProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicMap;
|
||||
import org.graalvm.compiler.core.common.SuppressFBWarnings;
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalRuntime;
|
||||
import org.graalvm.compiler.options.OptionDescriptor;
|
||||
import org.graalvm.compiler.options.OptionDescriptors;
|
||||
import org.graalvm.compiler.options.OptionsParser;
|
||||
import org.graalvm.compiler.serviceprovider.GraalServices;
|
||||
|
||||
import jdk.vm.ci.services.Services;
|
||||
|
||||
/**
|
||||
* MBean used to access properties and operations of a {@link HotSpotGraalRuntime} instance.
|
||||
*/
|
||||
public final class HotSpotGraalRuntimeMBean implements DynamicMBean {
|
||||
|
||||
/**
|
||||
* The runtime instance to which this bean provides a management connection.
|
||||
*/
|
||||
private final HotSpotGraalRuntime runtime;
|
||||
|
||||
/**
|
||||
* The object name under which the bean is registered.
|
||||
*/
|
||||
private final ObjectName objectName;
|
||||
|
||||
public HotSpotGraalRuntimeMBean(ObjectName objectName, HotSpotGraalRuntime runtime) {
|
||||
this.objectName = objectName;
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
public HotSpotGraalRuntime getRuntime() {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
private static final boolean DEBUG = initDebug();
|
||||
|
||||
private static boolean initDebug() {
|
||||
try {
|
||||
return Boolean.parseBoolean(Services.getSavedProperties().get(HotSpotGraalRuntimeMBean.class.getSimpleName() + ".debug"));
|
||||
} catch (SecurityException e) {
|
||||
// Swallow the exception
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) throws AttributeNotFoundException {
|
||||
String[] result = runtime.getOptionValues(name);
|
||||
String value = result[0];
|
||||
if (value == null) {
|
||||
throw new AttributeNotFoundException(name);
|
||||
}
|
||||
if (DEBUG) {
|
||||
System.out.printf("getAttribute: %s = %s (type: %s)%n", name, value, value == null ? "null" : value.getClass().getName());
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality on the receiver is what we want")
|
||||
@Override
|
||||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException {
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
String svalue = String.valueOf(value);
|
||||
if (DEBUG) {
|
||||
System.out.printf("setAttribute: %s = %s (type: %s)%n", name, svalue, value == null ? "null" : value.getClass().getName());
|
||||
}
|
||||
String[] result = runtime.setOptionValues(new String[]{name}, new String[]{svalue});
|
||||
if (result[0] != name) {
|
||||
if (result[0] == null) {
|
||||
throw new AttributeNotFoundException(name);
|
||||
}
|
||||
throw new InvalidAttributeValueException(result[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(String[] names) {
|
||||
String[] values = runtime.getOptionValues(names);
|
||||
AttributeList list = new AttributeList();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String value = values[i];
|
||||
String name = names[i];
|
||||
if (value == null) {
|
||||
TTY.printf("No such option named %s%n", name);
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.out.printf("getAttributes: %s = %s (type: %s)%n", name, value, value == null ? "null" : value.getClass().getName());
|
||||
}
|
||||
list.add(new Attribute(name, value));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality on the receiver is what we want")
|
||||
@Override
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
String[] names = new String[attributes.size()];
|
||||
String[] values = new String[attributes.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Attribute attr : attributes.asList()) {
|
||||
String name = attr.getName();
|
||||
names[i] = name;
|
||||
Object value = attr.getValue();
|
||||
String svalue = String.valueOf(value);
|
||||
values[i] = svalue;
|
||||
if (DEBUG) {
|
||||
System.out.printf("setAttributes: %s = %s (type: %s)%n", name, svalue, value == null ? "null" : value.getClass().getName());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
String[] result = runtime.setOptionValues(names, values);
|
||||
AttributeList setOk = new AttributeList();
|
||||
i = 0;
|
||||
for (Attribute attr : attributes.asList()) {
|
||||
if (names[i] == result[i]) {
|
||||
setOk.add(attr);
|
||||
} else if (result[i] == null) {
|
||||
TTY.printf("Error setting %s to %s: unknown option%n", attr.getName(), attr.getValue());
|
||||
} else {
|
||||
TTY.printf("Error setting %s to %s: %s%n", attr.getName(), attr.getValue(), result[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return setOk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
|
||||
try {
|
||||
if (DEBUG) {
|
||||
System.out.printf("invoke: %s%s%n", actionName, Arrays.asList(params));
|
||||
}
|
||||
Object retvalue = null;
|
||||
if ("dumpMethod".equals(actionName)) {
|
||||
retvalue = runtime.invokeManagementAction(actionName, params);
|
||||
} else {
|
||||
boolean found = false;
|
||||
for (HotSpotMBeanOperationProvider p : GraalServices.load(HotSpotMBeanOperationProvider.class)) {
|
||||
List<MBeanOperationInfo> info = new ArrayList<>();
|
||||
p.registerOperations(MBeanOperationInfo.class, info);
|
||||
for (MBeanOperationInfo op : info) {
|
||||
if (actionName.equals(op.getName())) {
|
||||
retvalue = p.invoke(actionName, params, signature);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new MBeanException(new IllegalStateException("Cannot find operation " + actionName));
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
System.out.printf("invoke: %s%s = %s%n", actionName, Arrays.asList(params), retvalue);
|
||||
}
|
||||
return retvalue;
|
||||
} catch (MBeanException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new ReflectionException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
List<MBeanAttributeInfo> attrs = new ArrayList<>();
|
||||
for (OptionDescriptor option : getOptionDescriptors().getValues()) {
|
||||
Class<?> optionValueType = option.getOptionValueType();
|
||||
if (Enum.class.isAssignableFrom(optionValueType)) {
|
||||
// Enum values are passed through
|
||||
// the management interface as Strings.
|
||||
optionValueType = String.class;
|
||||
}
|
||||
attrs.add(new MBeanAttributeInfo(option.getName(), optionValueType.getName(), option.getHelp(), true, true, false));
|
||||
}
|
||||
attrs.sort(new Comparator<MBeanAttributeInfo>() {
|
||||
@Override
|
||||
public int compare(MBeanAttributeInfo o1, MBeanAttributeInfo o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
List<MBeanOperationInfo> opts = new ArrayList<>();
|
||||
opts.add(new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
|
||||
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
||||
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
||||
}, "void", MBeanOperationInfo.ACTION));
|
||||
opts.add(new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
|
||||
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
||||
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
||||
new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
|
||||
}, "void", MBeanOperationInfo.ACTION));
|
||||
opts.add(new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{
|
||||
new MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
||||
new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
||||
new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
|
||||
new MBeanParameterInfo("host", "java.lang.String", "The host where the IGV tool is running at"),
|
||||
new MBeanParameterInfo("port", "int", "The port where the IGV tool is listening at"),
|
||||
}, "void", MBeanOperationInfo.ACTION));
|
||||
|
||||
for (HotSpotMBeanOperationProvider p : GraalServices.load(HotSpotMBeanOperationProvider.class)) {
|
||||
p.registerOperations(MBeanOperationInfo.class, opts);
|
||||
}
|
||||
|
||||
return new MBeanInfo(
|
||||
HotSpotGraalRuntimeMBean.class.getName(),
|
||||
"Graal",
|
||||
attrs.toArray(new MBeanAttributeInfo[attrs.size()]),
|
||||
null,
|
||||
opts.toArray(new MBeanOperationInfo[opts.size()]),
|
||||
null);
|
||||
}
|
||||
|
||||
private static EconomicMap<String, OptionDescriptor> getOptionDescriptors() {
|
||||
EconomicMap<String, OptionDescriptor> result = EconomicMap.create();
|
||||
for (OptionDescriptors set : OptionsParser.getOptionsLoader()) {
|
||||
for (OptionDescriptor option : set) {
|
||||
result.put(option.getName(), option);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicMap;
|
||||
import jdk.internal.vm.compiler.collections.EconomicSet;
|
||||
import jdk.internal.vm.compiler.collections.Equivalence;
|
||||
import jdk.internal.vm.compiler.collections.UnmodifiableEconomicSet;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EconomicMapImplTest {
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testRemoveNull() {
|
||||
EconomicMap<Integer, Integer> map = EconomicMap.create(10);
|
||||
map.removeKey(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitFromHashSet() {
|
||||
UnmodifiableEconomicSet<Integer> set = new UnmodifiableEconomicSet<Integer>() {
|
||||
|
||||
@Override
|
||||
public boolean contains(Integer element) {
|
||||
return element == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new Iterator<Integer>() {
|
||||
|
||||
private boolean visited = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return !visited;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
if (visited) {
|
||||
return null;
|
||||
} else {
|
||||
visited = true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
EconomicSet<Integer> newSet = EconomicSet.create(Equivalence.DEFAULT, set);
|
||||
Assert.assertEquals(newSet.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyHash() {
|
||||
EconomicSet<Integer> set = EconomicSet.create(Equivalence.IDENTITY);
|
||||
set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
|
||||
EconomicSet<Integer> newSet = EconomicSet.create(Equivalence.IDENTITY, set);
|
||||
Assert.assertEquals(newSet.size(), 10);
|
||||
newSet.remove(8);
|
||||
newSet.remove(9);
|
||||
Assert.assertEquals(newSet.size(), 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewEquivalence() {
|
||||
EconomicSet<Integer> set = EconomicSet.create(new Equivalence() {
|
||||
@Override
|
||||
public boolean equals(Object a, Object b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
|
||||
Assert.assertTrue(set.add(newInteger(0)));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"deprecation", "removal", "unused"})
|
||||
private static Integer newInteger(int value) {
|
||||
return new Integer(value);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testMapPutNull() {
|
||||
EconomicMap<Integer, Integer> map = EconomicMap.create();
|
||||
map.put(null, null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicMap;
|
||||
import jdk.internal.vm.compiler.collections.Equivalence;
|
||||
import jdk.internal.vm.compiler.collections.MapCursor;
|
||||
import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class EconomicMapLargeTest {
|
||||
|
||||
@Parameter(value = 0) public EconomicMap<Object, Object> testMap;
|
||||
@Parameter(value = 1) public EconomicMap<Object, Object> referenceMap;
|
||||
@Parameter(value = 2) public String name;
|
||||
|
||||
@Parameters(name = "{2}")
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.create(Equivalence.DEFAULT), "EconomicMap"},
|
||||
new Object[]{EconomicMap.create(Equivalence.IDENTITY), EconomicMap.create(Equivalence.IDENTITY), "EconomicMap(IDENTITY)"},
|
||||
new Object[]{EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE), EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE),
|
||||
"EconomicMap(IDENTITY_WITH_SYSTEM_HASHCODE)"},
|
||||
new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.wrapMap(new LinkedHashMap<>()), "EconomicMap<->wrapMap"},
|
||||
new Object[]{EconomicMap.wrapMap(new LinkedHashMap<>()), EconomicMap.wrapMap(new LinkedHashMap<>()), "wrapMap"});
|
||||
}
|
||||
|
||||
private static int[] createRandomRange(Random random, int count) {
|
||||
int[] result = new int[count];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
int range = random.nextInt(14);
|
||||
if (range == 0 || range > 10) {
|
||||
range = Integer.MAX_VALUE;
|
||||
} else if (range == 10) {
|
||||
range = 100;
|
||||
}
|
||||
result[i] = range;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class BadHashClass {
|
||||
private int value;
|
||||
|
||||
BadHashClass(int randomInt) {
|
||||
this.value = randomInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof BadHashClass) {
|
||||
BadHashClass badHashClass = (BadHashClass) other;
|
||||
return badHashClass.value == value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
interface MapAction {
|
||||
Object perform(EconomicMap<Object, Object> map, int randomInt);
|
||||
}
|
||||
|
||||
static final Object EXISTING_VALUE = new Object();
|
||||
|
||||
static final MapAction[] INCREASE_ACTIONS = new MapAction[]{
|
||||
(map, randomInt) -> map.put(randomInt, "value"),
|
||||
(map, randomInt) -> map.get(randomInt)
|
||||
};
|
||||
|
||||
static final MapAction[] ACTIONS = new MapAction[]{
|
||||
(map, randomInt) -> map.removeKey(randomInt),
|
||||
(map, randomInt) -> map.put(randomInt, "value"),
|
||||
(map, randomInt) -> map.put(randomInt, null),
|
||||
(map, randomInt) -> map.put(EXISTING_VALUE, randomInt),
|
||||
(map, randomInt) -> {
|
||||
if (randomInt == 0) {
|
||||
map.clear();
|
||||
}
|
||||
return map.isEmpty();
|
||||
},
|
||||
(map, randomInt) -> map.containsKey(randomInt),
|
||||
(map, randomInt) -> map.get(randomInt),
|
||||
(map, randomInt) -> map.put(new BadHashClass(randomInt), "unique"),
|
||||
(map, randomInt) -> {
|
||||
if (randomInt == 0) {
|
||||
map.replaceAll((key, value) -> Objects.toString(value) + "!");
|
||||
}
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testVeryLarge() {
|
||||
testMap.clear();
|
||||
referenceMap.clear();
|
||||
|
||||
Random random = new Random(0);
|
||||
for (int i = 0; i < 200000; ++i) {
|
||||
for (int j = 0; j < INCREASE_ACTIONS.length; ++j) {
|
||||
int nextInt = random.nextInt(10000000);
|
||||
MapAction action = INCREASE_ACTIONS[j];
|
||||
Object result = action.perform(testMap, nextInt);
|
||||
Object referenceResult = action.perform(referenceMap, nextInt);
|
||||
Assert.assertEquals(result, referenceResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a sequence of random operations on the map.
|
||||
*/
|
||||
@Test
|
||||
public void testAddRemove() {
|
||||
testMap.clear();
|
||||
referenceMap.clear();
|
||||
|
||||
for (int seed = 0; seed < 10; ++seed) {
|
||||
Random random = new Random(seed);
|
||||
int[] ranges = createRandomRange(random, ACTIONS.length);
|
||||
int value = random.nextInt(10000);
|
||||
for (int i = 0; i < value; ++i) {
|
||||
for (int j = 0; j < ACTIONS.length; ++j) {
|
||||
if (random.nextInt(ranges[j]) == 0) {
|
||||
int nextInt = random.nextInt(100);
|
||||
MapAction action = ACTIONS[j];
|
||||
Object result = action.perform(testMap, nextInt);
|
||||
Object referenceResult = action.perform(referenceMap, nextInt);
|
||||
Assert.assertEquals(result, referenceResult);
|
||||
if (j % 100 == 0) {
|
||||
checkEquality(testMap, referenceMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (random.nextInt(20) == 0) {
|
||||
removeElement(random.nextInt(100), testMap, referenceMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeElement(int index, EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
|
||||
Assert.assertEquals(referenceMap.size(), map.size());
|
||||
MapCursor<?, ?> cursor = map.getEntries();
|
||||
MapCursor<?, ?> referenceCursor = referenceMap.getEntries();
|
||||
int z = 0;
|
||||
while (cursor.advance()) {
|
||||
Assert.assertTrue(referenceCursor.advance());
|
||||
Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
|
||||
Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
|
||||
if (index == z) {
|
||||
cursor.remove();
|
||||
referenceCursor.remove();
|
||||
}
|
||||
++z;
|
||||
}
|
||||
|
||||
Assert.assertFalse(referenceCursor.advance());
|
||||
}
|
||||
|
||||
private static void checkEquality(EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
|
||||
Assert.assertEquals(referenceMap.size(), map.size());
|
||||
|
||||
// Check entries.
|
||||
UnmodifiableMapCursor<?, ?> cursor = map.getEntries();
|
||||
UnmodifiableMapCursor<?, ?> referenceCursor = referenceMap.getEntries();
|
||||
while (cursor.advance()) {
|
||||
Assert.assertTrue(referenceCursor.advance());
|
||||
Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
|
||||
Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
|
||||
}
|
||||
|
||||
// Check keys.
|
||||
Iterator<?> iterator = map.getKeys().iterator();
|
||||
Iterator<?> referenceIterator = referenceMap.getKeys().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Assert.assertTrue(referenceIterator.hasNext());
|
||||
Assert.assertEquals(iterator.next(), referenceIterator.next());
|
||||
}
|
||||
|
||||
// Check values.
|
||||
iterator = map.getValues().iterator();
|
||||
referenceIterator = referenceMap.getValues().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Assert.assertTrue(referenceIterator.hasNext());
|
||||
Assert.assertEquals(iterator.next(), referenceIterator.next());
|
||||
}
|
||||
Assert.assertFalse(referenceIterator.hasNext());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicMap;
|
||||
import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EconomicMapTest {
|
||||
|
||||
@Test
|
||||
public void testMapGetDefault() {
|
||||
EconomicMap<Integer, Integer> map = EconomicMap.create();
|
||||
map.put(0, 1);
|
||||
Assert.assertEquals(map.get(0, 2), Integer.valueOf(1));
|
||||
Assert.assertEquals(map.get(1, 2), Integer.valueOf(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapPutAll() {
|
||||
EconomicMap<Integer, Integer> map = EconomicMap.create();
|
||||
EconomicMap<Integer, Integer> newMap = EconomicMap.wrapMap(new LinkedHashMap<>());
|
||||
newMap.put(1, 1);
|
||||
newMap.put(2, 4);
|
||||
map.putAll(newMap);
|
||||
Assert.assertEquals(map.size(), 2);
|
||||
|
||||
UnmodifiableEconomicMap<Integer, Integer> unmodifiableEconomicMap = EconomicMap.create(newMap);
|
||||
|
||||
map.removeKey(1);
|
||||
map.put(2, 2);
|
||||
map.put(3, 9);
|
||||
|
||||
map.putAll(unmodifiableEconomicMap);
|
||||
Assert.assertEquals(map.size(), 3);
|
||||
Assert.assertEquals(map.get(2), Integer.valueOf(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
EconomicMap<Integer, Integer> map = EconomicMap.create();
|
||||
map.put(0, 0);
|
||||
map.put(1, 1);
|
||||
Assert.assertEquals(map.toString(), "map(size=2, {(0,0),(1,1)})");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.EconomicSet;
|
||||
import jdk.internal.vm.compiler.collections.Equivalence;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EconomicSetTest {
|
||||
|
||||
@Test
|
||||
public void testUtilities() {
|
||||
EconomicSet<Integer> set = EconomicSet.create(0);
|
||||
set.add(0);
|
||||
Assert.assertTrue(set.add(1));
|
||||
Assert.assertEquals(set.size(), 2);
|
||||
Assert.assertFalse(set.add(1));
|
||||
Assert.assertEquals(set.size(), 2);
|
||||
set.remove(1);
|
||||
Assert.assertEquals(set.size(), 1);
|
||||
set.remove(2);
|
||||
Assert.assertEquals(set.size(), 1);
|
||||
Assert.assertTrue(set.add(1));
|
||||
set.clear();
|
||||
Assert.assertEquals(set.size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAll() {
|
||||
EconomicSet<Integer> set = EconomicSet.create();
|
||||
set.addAll(Arrays.asList(0, 1, 0));
|
||||
Assert.assertEquals(set.size(), 2);
|
||||
|
||||
EconomicSet<Integer> newSet = EconomicSet.create();
|
||||
newSet.addAll(Arrays.asList(1, 2));
|
||||
Assert.assertEquals(newSet.size(), 2);
|
||||
newSet.addAll(set);
|
||||
Assert.assertEquals(newSet.size(), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAll() {
|
||||
EconomicSet<Integer> set = EconomicSet.create();
|
||||
set.addAll(Arrays.asList(0, 1));
|
||||
|
||||
set.removeAll(Arrays.asList(1, 2));
|
||||
Assert.assertEquals(set.size(), 1);
|
||||
|
||||
set.removeAll(EconomicSet.create(set));
|
||||
Assert.assertEquals(set.size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetainAll() {
|
||||
EconomicSet<Integer> set = EconomicSet.create();
|
||||
set.addAll(Arrays.asList(0, 1, 2));
|
||||
|
||||
EconomicSet<Integer> newSet = EconomicSet.create();
|
||||
newSet.addAll(Arrays.asList(2, 3));
|
||||
|
||||
set.retainAll(newSet);
|
||||
Assert.assertEquals(set.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToArray() {
|
||||
EconomicSet<Integer> set = EconomicSet.create();
|
||||
set.addAll(Arrays.asList(0, 1));
|
||||
Assert.assertArrayEquals(set.toArray(new Integer[2]), new Integer[]{0, 1});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
EconomicSet<Integer> set = EconomicSet.create();
|
||||
set.addAll(Arrays.asList(0, 1));
|
||||
Assert.assertEquals(set.toString(), "set(size=2, {0,1})");
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testToUnalignedArray() {
|
||||
Assert.assertArrayEquals(EconomicSet.create().toArray(new Integer[2]), new Integer[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRemoval() {
|
||||
ArrayList<Integer> initialList = new ArrayList<>();
|
||||
ArrayList<Integer> removalList = new ArrayList<>();
|
||||
ArrayList<Integer> finalList = new ArrayList<>();
|
||||
EconomicSet<Integer> set = EconomicSet.create(Equivalence.IDENTITY);
|
||||
set.add(1);
|
||||
set.add(2);
|
||||
set.add(3);
|
||||
set.add(4);
|
||||
set.add(5);
|
||||
set.add(6);
|
||||
set.add(7);
|
||||
set.add(8);
|
||||
set.add(9);
|
||||
Iterator<Integer> i1 = set.iterator();
|
||||
while (i1.hasNext()) {
|
||||
initialList.add(i1.next());
|
||||
}
|
||||
int size = 0;
|
||||
Iterator<Integer> i2 = set.iterator();
|
||||
while (i2.hasNext()) {
|
||||
Integer elem = i2.next();
|
||||
if (size++ < 8) {
|
||||
i2.remove();
|
||||
}
|
||||
removalList.add(elem);
|
||||
}
|
||||
Iterator<Integer> i3 = set.iterator();
|
||||
while (i3.hasNext()) {
|
||||
finalList.add(i3.next());
|
||||
}
|
||||
Assert.assertEquals(initialList, removalList);
|
||||
Assert.assertEquals(1, finalList.size());
|
||||
Assert.assertEquals(newInteger(9), finalList.get(0));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"deprecation", "removal", "unused"})
|
||||
private static Integer newInteger(int value) {
|
||||
return new Integer(value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.Equivalence;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EquivalenceTest {
|
||||
|
||||
private static final String TEST_STRING = "Graal";
|
||||
private static final String TEST_STRING2 = "Graal2";
|
||||
|
||||
@Test
|
||||
public void testDEFAULT() {
|
||||
Assert.assertTrue(Equivalence.DEFAULT.equals(TEST_STRING, new String(TEST_STRING)));
|
||||
Assert.assertEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(new String(TEST_STRING)));
|
||||
Assert.assertFalse(Equivalence.DEFAULT.equals(TEST_STRING, TEST_STRING2));
|
||||
Assert.assertNotEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(TEST_STRING2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIDENTITY() {
|
||||
Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, new String(TEST_STRING)));
|
||||
Assert.assertEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(new String(TEST_STRING)));
|
||||
Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, TEST_STRING2));
|
||||
Assert.assertNotEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(TEST_STRING2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIDENTITYWITHSYSTEMHASHCODE() {
|
||||
Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, new String(TEST_STRING)));
|
||||
Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(new String(TEST_STRING)));
|
||||
Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, TEST_STRING2));
|
||||
Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING2));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections.test;
|
||||
|
||||
import jdk.internal.vm.compiler.collections.Pair;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PairTest {
|
||||
|
||||
@Test
|
||||
public void testCreate() {
|
||||
Assert.assertEquals(Pair.create(null, null), Pair.empty());
|
||||
Assert.assertNotEquals(Pair.create(null, null), null);
|
||||
Assert.assertEquals(Pair.createLeft(null), Pair.empty());
|
||||
Assert.assertEquals(Pair.createRight(null), Pair.empty());
|
||||
Assert.assertEquals(Pair.create(1, null), Pair.createLeft(1));
|
||||
Assert.assertEquals(Pair.create(null, 1), Pair.createRight(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUtilities() {
|
||||
Pair<Integer, Integer> pair = Pair.create(1, null);
|
||||
Assert.assertEquals(pair.getLeft(), Integer.valueOf(1));
|
||||
Assert.assertEquals(pair.getRight(), null);
|
||||
Assert.assertEquals(pair.toString(), "(1, null)");
|
||||
Assert.assertEquals(pair.hashCode(), Pair.createLeft(1).hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Memory efficient map data structure that dynamically changes its representation depending on the
|
||||
* number of entries and is specially optimized for small number of entries. It keeps elements in a
|
||||
* linear list without any hashing when the number of entries is small. Should an actual hash data
|
||||
* structure be necessary, it tries to fit the hash value into as few bytes as possible. In contrast
|
||||
* to {@link java.util.HashMap}, it avoids allocating an extra node object per entry and rather
|
||||
* keeps values always in a plain array. See {@link EconomicMapImpl} for implementation details and
|
||||
* exact thresholds when its representation changes.
|
||||
*
|
||||
* It supports a {@code null} value, but it does not support adding or looking up a {@code null}
|
||||
* key. Operations {@code get} and {@code put} provide constant-time performance on average if
|
||||
* repeatedly performed. They can however trigger an operation growing or compressing the data
|
||||
* structure, which is linear in the number of elements. Iteration is also linear in the number of
|
||||
* elements.
|
||||
*
|
||||
* The implementation is not synchronized. If multiple threads want to access the data structure, it
|
||||
* requires manual synchronization, for example using {@link java.util.Collections#synchronizedMap}.
|
||||
* There is also no extra precaution to detect concurrent modification while iterating.
|
||||
*
|
||||
* Different strategies for the equality comparison can be configured by providing a
|
||||
* {@link Equivalence} configuration object.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
|
||||
|
||||
/**
|
||||
* Associates {@code value} with {@code key} in this map. If the map previously contained a
|
||||
* mapping for {@code key}, the old value is replaced by {@code value}. While the {@code value}
|
||||
* may be {@code null}, the {@code key} must not be {code null}.
|
||||
*
|
||||
* @return the previous value associated with {@code key}, or {@code null} if there was no
|
||||
* mapping for {@code key}.
|
||||
* @since 19.0
|
||||
*/
|
||||
V put(K key, V value);
|
||||
|
||||
/**
|
||||
* Copies all of the mappings from {@code other} to this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void putAll(EconomicMap<K, V> other) {
|
||||
MapCursor<K, V> e = other.getEntries();
|
||||
while (e.advance()) {
|
||||
put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all of the mappings from {@code other} to this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void putAll(UnmodifiableEconomicMap<? extends K, ? extends V> other) {
|
||||
UnmodifiableMapCursor<? extends K, ? extends V> entry = other.getEntries();
|
||||
while (entry.advance()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the mappings from this map. The map will be empty after this call returns.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Removes the mapping for {@code key} from this map if it is present. The map will not contain
|
||||
* a mapping for {@code key} once the call returns. The {@code key} must not be {@code null}.
|
||||
*
|
||||
* @return the previous value associated with {@code key}, or {@code null} if there was no
|
||||
* mapping for {@code key}.
|
||||
* @since 19.0
|
||||
*/
|
||||
V removeKey(K key);
|
||||
|
||||
/**
|
||||
* Returns a {@link MapCursor} view of the mappings contained in this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@Override
|
||||
MapCursor<K, V> getEntries();
|
||||
|
||||
/**
|
||||
* Replaces each entry's value with the result of invoking {@code function} on that entry until
|
||||
* all entries have been processed or the function throws an exception. Exceptions thrown by the
|
||||
* function are relayed to the caller.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function);
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set with the default
|
||||
* {@link Equivalence#DEFAULT} comparison strategy for keys.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create() {
|
||||
return EconomicMap.create(Equivalence.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set with the default
|
||||
* {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified
|
||||
* capacity.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create(int initialCapacity) {
|
||||
return EconomicMap.create(Equivalence.DEFAULT, initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set with the given comparison
|
||||
* strategy for keys.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create(Equivalence strategy) {
|
||||
return EconomicMapImpl.create(strategy, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set with the default
|
||||
* {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the
|
||||
* specified existing map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create(UnmodifiableEconomicMap<K, V> m) {
|
||||
return EconomicMap.create(Equivalence.DEFAULT, m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set and copies all elements from
|
||||
* the specified existing map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> m) {
|
||||
return EconomicMapImpl.create(strategy, m, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map that guarantees insertion order on the key set and initializes with a
|
||||
* specified capacity.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> create(Equivalence strategy, int initialCapacity) {
|
||||
return EconomicMapImpl.create(strategy, initialCapacity, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an existing {@link Map} as an {@link EconomicMap}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <K, V> EconomicMap<K, V> wrapMap(Map<K, V> map) {
|
||||
return new EconomicMap<K, V>() {
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
V result = map.get(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
V result = map.put(key, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
int result = map.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V removeKey(K key) {
|
||||
V result = map.remove(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<V> getValues() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCursor<K, V> getEntries() {
|
||||
Iterator<java.util.Map.Entry<K, V>> iterator = map.entrySet().iterator();
|
||||
return new MapCursor<K, V>() {
|
||||
|
||||
private Map.Entry<K, V> current;
|
||||
|
||||
@Override
|
||||
public boolean advance() {
|
||||
boolean result = iterator.hasNext();
|
||||
if (result) {
|
||||
current = iterator.next();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return current.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return current.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
||||
map.replaceAll(function);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,874 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Implementation of a map with a memory-efficient structure that always preserves insertion order
|
||||
* when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal
|
||||
* {@link #INITIAL_CAPACITY} or smaller 256.
|
||||
*
|
||||
* The key/value pairs are kept in an expanding flat object array with keys at even indices and
|
||||
* values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there
|
||||
* is no additional hash data structure and comparisons are done via linear checking of the
|
||||
* key/value pairs. For the case where the equality check is particularly cheap (e.g., just an
|
||||
* object identity comparison), this limit below which the map is without an actual hash table is
|
||||
* higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}.
|
||||
*
|
||||
* When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash
|
||||
* array where an entry of 0 means no hit and otherwise denotes the entry number in the
|
||||
* {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit
|
||||
* within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of
|
||||
* integer values in other cases.
|
||||
*
|
||||
* Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take
|
||||
* the place of the values in the {@link #entries} array.
|
||||
*
|
||||
* Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the
|
||||
* map falls below a specific threshold, the map will be compressed via the
|
||||
* {@link #maybeCompress(int)} method.
|
||||
*/
|
||||
final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
|
||||
|
||||
/**
|
||||
* Initial number of key/value pair entries that is allocated in the first entries array.
|
||||
*/
|
||||
private static final int INITIAL_CAPACITY = 4;
|
||||
|
||||
/**
|
||||
* Maximum number of entries that are moved linearly forward if a key is removed.
|
||||
*/
|
||||
private static final int COMPRESS_IMMEDIATE_CAPACITY = 8;
|
||||
|
||||
/**
|
||||
* Minimum number of key/value pair entries added when the entries array is increased in size.
|
||||
*/
|
||||
private static final int MIN_CAPACITY_INCREASE = 8;
|
||||
|
||||
/**
|
||||
* Number of entries above which a hash table is created.
|
||||
*/
|
||||
private static final int HASH_THRESHOLD = 4;
|
||||
|
||||
/**
|
||||
* Number of entries above which a hash table is created when equality can be checked with
|
||||
* object identity.
|
||||
*/
|
||||
private static final int HASH_THRESHOLD_IDENTITY_COMPARE = 8;
|
||||
|
||||
/**
|
||||
* Maximum number of entries allowed in the map.
|
||||
*/
|
||||
private static final int MAX_ELEMENT_COUNT = Integer.MAX_VALUE >> 1;
|
||||
|
||||
/**
|
||||
* Number of entries above which more than 1 byte is necessary for the hash index.
|
||||
*/
|
||||
private static final int LARGE_HASH_THRESHOLD = ((1 << Byte.SIZE) << 1);
|
||||
|
||||
/**
|
||||
* Number of entries above which more than 2 bytes are are necessary for the hash index.
|
||||
*/
|
||||
private static final int VERY_LARGE_HASH_THRESHOLD = (LARGE_HASH_THRESHOLD << Byte.SIZE);
|
||||
|
||||
/**
|
||||
* Total number of entries (actual entries plus deleted entries).
|
||||
*/
|
||||
private int totalEntries;
|
||||
|
||||
/**
|
||||
* Number of deleted entries.
|
||||
*/
|
||||
private int deletedEntries;
|
||||
|
||||
/**
|
||||
* Entries array with even indices storing keys and odd indices storing values.
|
||||
*/
|
||||
private Object[] entries;
|
||||
|
||||
/**
|
||||
* Hash array that is interpreted either as byte or short or int array depending on number of
|
||||
* map entries.
|
||||
*/
|
||||
private byte[] hashArray;
|
||||
|
||||
/**
|
||||
* The strategy used for comparing keys or {@code null} for denoting special strategy
|
||||
* {@link Equivalence#IDENTITY}.
|
||||
*/
|
||||
private final Equivalence strategy;
|
||||
|
||||
/**
|
||||
* Intercept method for debugging purposes.
|
||||
*/
|
||||
private static <K, V> EconomicMapImpl<K, V> intercept(EconomicMapImpl<K, V> map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, boolean isSet) {
|
||||
return intercept(new EconomicMapImpl<>(strategy, isSet));
|
||||
}
|
||||
|
||||
public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, int initialCapacity, boolean isSet) {
|
||||
return intercept(new EconomicMapImpl<>(strategy, initialCapacity, isSet));
|
||||
}
|
||||
|
||||
public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> other, boolean isSet) {
|
||||
return intercept(new EconomicMapImpl<>(strategy, other, isSet));
|
||||
}
|
||||
|
||||
public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicSet<K> other, boolean isSet) {
|
||||
return intercept(new EconomicMapImpl<>(strategy, other, isSet));
|
||||
}
|
||||
|
||||
private EconomicMapImpl(Equivalence strategy, boolean isSet) {
|
||||
if (strategy == Equivalence.IDENTITY) {
|
||||
this.strategy = null;
|
||||
} else {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
this.isSet = isSet;
|
||||
}
|
||||
|
||||
private EconomicMapImpl(Equivalence strategy, int initialCapacity, boolean isSet) {
|
||||
this(strategy, isSet);
|
||||
init(initialCapacity);
|
||||
}
|
||||
|
||||
private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicMap<K, V> other, boolean isSet) {
|
||||
this(strategy, isSet);
|
||||
if (!initFrom(other)) {
|
||||
init(other.size());
|
||||
putAll(other);
|
||||
}
|
||||
}
|
||||
|
||||
private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicSet<K> other, boolean isSet) {
|
||||
this(strategy, isSet);
|
||||
if (!initFrom(other)) {
|
||||
init(other.size());
|
||||
addAll(other);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean initFrom(Object o) {
|
||||
if (o instanceof EconomicMapImpl) {
|
||||
EconomicMapImpl<K, V> otherMap = (EconomicMapImpl<K, V>) o;
|
||||
// We are only allowed to directly copy if the strategies of the two maps are the same.
|
||||
if (strategy == otherMap.strategy) {
|
||||
totalEntries = otherMap.totalEntries;
|
||||
deletedEntries = otherMap.deletedEntries;
|
||||
if (otherMap.entries != null) {
|
||||
entries = otherMap.entries.clone();
|
||||
}
|
||||
if (otherMap.hashArray != null) {
|
||||
hashArray = otherMap.hashArray.clone();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init(int size) {
|
||||
if (size > INITIAL_CAPACITY) {
|
||||
entries = new Object[size << 1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the collisions. Needs to be immutable class for allowing efficient shallow copy from
|
||||
* other map on construction.
|
||||
*/
|
||||
private static final class CollisionLink {
|
||||
|
||||
CollisionLink(Object value, int next) {
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
final Object value;
|
||||
|
||||
/**
|
||||
* Index plus one of the next entry in the collision link chain.
|
||||
*/
|
||||
final int next;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V get(K key) {
|
||||
checkKeyNonNull(key);
|
||||
|
||||
int index = find(key);
|
||||
if (index != -1) {
|
||||
return (V) getValue(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int find(K key) {
|
||||
if (hasHashArray()) {
|
||||
return findHash(key);
|
||||
} else {
|
||||
return findLinear(key);
|
||||
}
|
||||
}
|
||||
|
||||
private int findLinear(K key) {
|
||||
for (int i = 0; i < totalEntries; i++) {
|
||||
Object entryKey = entries[i << 1];
|
||||
if (entryKey != null && compareKeys(key, entryKey)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean compareKeys(Object key, Object entryKey) {
|
||||
if (key == entryKey) {
|
||||
return true;
|
||||
}
|
||||
if (strategy != null && strategy != Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
|
||||
if (strategy == Equivalence.DEFAULT) {
|
||||
return key.equals(entryKey);
|
||||
} else {
|
||||
return strategy.equals(key, entryKey);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int findHash(K key) {
|
||||
int index = getHashArray(getHashIndex(key)) - 1;
|
||||
if (index != -1) {
|
||||
Object entryKey = getKey(index);
|
||||
if (compareKeys(key, entryKey)) {
|
||||
return index;
|
||||
} else {
|
||||
Object entryValue = getRawValue(index);
|
||||
if (entryValue instanceof CollisionLink) {
|
||||
return findWithCollision(key, (CollisionLink) entryValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int findWithCollision(K key, CollisionLink initialEntryValue) {
|
||||
int index;
|
||||
Object entryKey;
|
||||
CollisionLink entryValue = initialEntryValue;
|
||||
while (true) {
|
||||
CollisionLink collisionLink = entryValue;
|
||||
index = collisionLink.next;
|
||||
entryKey = getKey(index);
|
||||
if (compareKeys(key, entryKey)) {
|
||||
return index;
|
||||
} else {
|
||||
Object value = getRawValue(index);
|
||||
if (value instanceof CollisionLink) {
|
||||
entryValue = (CollisionLink) getRawValue(index);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getHashArray(int index) {
|
||||
if (entries.length < LARGE_HASH_THRESHOLD) {
|
||||
return (hashArray[index] & 0xFF);
|
||||
} else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
|
||||
int adjustedIndex = index << 1;
|
||||
return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8);
|
||||
} else {
|
||||
int adjustedIndex = index << 2;
|
||||
return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8) | ((hashArray[adjustedIndex + 2] & 0xFF) << 16) | ((hashArray[adjustedIndex + 3] & 0xFF) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
private void setHashArray(int index, int value) {
|
||||
if (entries.length < LARGE_HASH_THRESHOLD) {
|
||||
hashArray[index] = (byte) value;
|
||||
} else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
|
||||
int adjustedIndex = index << 1;
|
||||
hashArray[adjustedIndex] = (byte) value;
|
||||
hashArray[adjustedIndex + 1] = (byte) (value >> 8);
|
||||
} else {
|
||||
int adjustedIndex = index << 2;
|
||||
hashArray[adjustedIndex] = (byte) value;
|
||||
hashArray[adjustedIndex + 1] = (byte) (value >> 8);
|
||||
hashArray[adjustedIndex + 2] = (byte) (value >> 16);
|
||||
hashArray[adjustedIndex + 3] = (byte) (value >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
private int findAndRemoveHash(Object key) {
|
||||
int hashIndex = getHashIndex(key);
|
||||
int index = getHashArray(hashIndex) - 1;
|
||||
if (index != -1) {
|
||||
Object entryKey = getKey(index);
|
||||
if (compareKeys(key, entryKey)) {
|
||||
Object value = getRawValue(index);
|
||||
int nextIndex = -1;
|
||||
if (value instanceof CollisionLink) {
|
||||
CollisionLink collisionLink = (CollisionLink) value;
|
||||
nextIndex = collisionLink.next;
|
||||
}
|
||||
setHashArray(hashIndex, nextIndex + 1);
|
||||
return index;
|
||||
} else {
|
||||
Object entryValue = getRawValue(index);
|
||||
if (entryValue instanceof CollisionLink) {
|
||||
return findAndRemoveWithCollision(key, (CollisionLink) entryValue, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryValue, int initialIndexValue) {
|
||||
int index;
|
||||
Object entryKey;
|
||||
CollisionLink entryValue = initialEntryValue;
|
||||
int lastIndex = initialIndexValue;
|
||||
while (true) {
|
||||
CollisionLink collisionLink = entryValue;
|
||||
index = collisionLink.next;
|
||||
entryKey = getKey(index);
|
||||
if (compareKeys(key, entryKey)) {
|
||||
Object value = getRawValue(index);
|
||||
if (value instanceof CollisionLink) {
|
||||
CollisionLink thisCollisionLink = (CollisionLink) value;
|
||||
setRawValue(lastIndex, new CollisionLink(collisionLink.value, thisCollisionLink.next));
|
||||
} else {
|
||||
setRawValue(lastIndex, collisionLink.value);
|
||||
}
|
||||
return index;
|
||||
} else {
|
||||
Object value = getRawValue(index);
|
||||
if (value instanceof CollisionLink) {
|
||||
entryValue = (CollisionLink) getRawValue(index);
|
||||
lastIndex = index;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getHashIndex(Object key) {
|
||||
int hash;
|
||||
if (strategy != null && strategy != Equivalence.DEFAULT) {
|
||||
if (strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
|
||||
hash = System.identityHashCode(key);
|
||||
} else {
|
||||
hash = strategy.hashCode(key);
|
||||
}
|
||||
} else {
|
||||
hash = key.hashCode();
|
||||
}
|
||||
hash = hash ^ (hash >>> 16);
|
||||
return hash & (getHashTableSize() - 1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
checkKeyNonNull(key);
|
||||
int index = find(key);
|
||||
if (index != -1) {
|
||||
Object oldValue = getValue(index);
|
||||
setValue(index, value);
|
||||
return (V) oldValue;
|
||||
}
|
||||
|
||||
int nextEntryIndex = totalEntries;
|
||||
if (entries == null) {
|
||||
entries = new Object[INITIAL_CAPACITY << 1];
|
||||
} else if (entries.length == nextEntryIndex << 1) {
|
||||
grow();
|
||||
|
||||
assert entries.length > totalEntries << 1;
|
||||
// Can change if grow is actually compressing.
|
||||
nextEntryIndex = totalEntries;
|
||||
}
|
||||
|
||||
setKey(nextEntryIndex, key);
|
||||
setValue(nextEntryIndex, value);
|
||||
totalEntries++;
|
||||
|
||||
if (hasHashArray()) {
|
||||
// Rehash on collision if hash table is more than three quarters full.
|
||||
boolean rehashOnCollision = (getHashTableSize() < (size() + (size() >> 1)));
|
||||
putHashEntry(key, nextEntryIndex, rehashOnCollision);
|
||||
} else if (totalEntries > getHashThreshold()) {
|
||||
createHash();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of entries above which a hash table should be constructed.
|
||||
*/
|
||||
private int getHashThreshold() {
|
||||
if (strategy == null || strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
|
||||
return HASH_THRESHOLD_IDENTITY_COMPARE;
|
||||
} else {
|
||||
return HASH_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
private void grow() {
|
||||
int entriesLength = entries.length;
|
||||
int newSize = (entriesLength >> 1) + Math.max(MIN_CAPACITY_INCREASE, entriesLength >> 2);
|
||||
if (newSize > MAX_ELEMENT_COUNT) {
|
||||
throw new UnsupportedOperationException("map grown too large!");
|
||||
}
|
||||
Object[] newEntries = new Object[newSize << 1];
|
||||
System.arraycopy(entries, 0, newEntries, 0, entriesLength);
|
||||
entries = newEntries;
|
||||
if ((entriesLength < LARGE_HASH_THRESHOLD && newEntries.length >= LARGE_HASH_THRESHOLD) ||
|
||||
(entriesLength < VERY_LARGE_HASH_THRESHOLD && newEntries.length > VERY_LARGE_HASH_THRESHOLD)) {
|
||||
// Rehash in order to change number of bits reserved for hash indices.
|
||||
createHash();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the graph if there is a large number of deleted entries and returns the translated
|
||||
* new next index.
|
||||
*/
|
||||
private int maybeCompress(int nextIndex) {
|
||||
if (entries.length != INITIAL_CAPACITY << 1 && deletedEntries >= (totalEntries >> 1) + (totalEntries >> 2)) {
|
||||
return compressLarge(nextIndex);
|
||||
}
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the graph and returns the translated new next index.
|
||||
*/
|
||||
private int compressLarge(int nextIndex) {
|
||||
int size = INITIAL_CAPACITY;
|
||||
int remaining = totalEntries - deletedEntries;
|
||||
|
||||
while (size <= remaining) {
|
||||
size += Math.max(MIN_CAPACITY_INCREASE, size >> 1);
|
||||
}
|
||||
|
||||
Object[] newEntries = new Object[size << 1];
|
||||
int z = 0;
|
||||
int newNextIndex = remaining;
|
||||
for (int i = 0; i < totalEntries; ++i) {
|
||||
Object key = getKey(i);
|
||||
if (i == nextIndex) {
|
||||
newNextIndex = z;
|
||||
}
|
||||
if (key != null) {
|
||||
newEntries[z << 1] = key;
|
||||
newEntries[(z << 1) + 1] = getValue(i);
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
this.entries = newEntries;
|
||||
totalEntries = z;
|
||||
deletedEntries = 0;
|
||||
if (z <= getHashThreshold()) {
|
||||
this.hashArray = null;
|
||||
} else {
|
||||
createHash();
|
||||
}
|
||||
return newNextIndex;
|
||||
}
|
||||
|
||||
private int getHashTableSize() {
|
||||
if (entries.length < LARGE_HASH_THRESHOLD) {
|
||||
return hashArray.length;
|
||||
} else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
|
||||
return hashArray.length >> 1;
|
||||
} else {
|
||||
return hashArray.length >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void createHash() {
|
||||
int entryCount = size();
|
||||
|
||||
// Calculate smallest 2^n that is greater number of entries.
|
||||
int size = getHashThreshold();
|
||||
while (size <= entryCount) {
|
||||
size <<= 1;
|
||||
}
|
||||
|
||||
// Give extra size to avoid collisions.
|
||||
size <<= 1;
|
||||
|
||||
if (this.entries.length >= VERY_LARGE_HASH_THRESHOLD) {
|
||||
// Every entry has 4 bytes.
|
||||
size <<= 2;
|
||||
} else if (this.entries.length >= LARGE_HASH_THRESHOLD) {
|
||||
// Every entry has 2 bytes.
|
||||
size <<= 1;
|
||||
} else {
|
||||
// Entries are very small => give extra size to further reduce collisions.
|
||||
size <<= 1;
|
||||
}
|
||||
|
||||
hashArray = new byte[size];
|
||||
for (int i = 0; i < totalEntries; i++) {
|
||||
Object entryKey = getKey(i);
|
||||
if (entryKey != null) {
|
||||
putHashEntry(entryKey, i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) {
|
||||
int hashIndex = getHashIndex(key);
|
||||
int oldIndex = getHashArray(hashIndex) - 1;
|
||||
if (oldIndex != -1 && rehashOnCollision) {
|
||||
this.createHash();
|
||||
return;
|
||||
}
|
||||
setHashArray(hashIndex, entryIndex + 1);
|
||||
Object value = getRawValue(entryIndex);
|
||||
if (oldIndex != -1) {
|
||||
assert entryIndex != oldIndex : "this cannot happend and would create an endless collision link cycle";
|
||||
if (value instanceof CollisionLink) {
|
||||
CollisionLink collisionLink = (CollisionLink) value;
|
||||
setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex));
|
||||
} else {
|
||||
setRawValue(entryIndex, new CollisionLink(getRawValue(entryIndex), oldIndex));
|
||||
}
|
||||
} else {
|
||||
if (value instanceof CollisionLink) {
|
||||
CollisionLink collisionLink = (CollisionLink) value;
|
||||
setRawValue(entryIndex, collisionLink.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return totalEntries - deletedEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return find(key) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
entries = null;
|
||||
hashArray = null;
|
||||
totalEntries = deletedEntries = 0;
|
||||
}
|
||||
|
||||
private boolean hasHashArray() {
|
||||
return hashArray != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V removeKey(K key) {
|
||||
checkKeyNonNull(key);
|
||||
int index;
|
||||
if (hasHashArray()) {
|
||||
index = this.findAndRemoveHash(key);
|
||||
} else {
|
||||
index = this.findLinear(key);
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
Object value = getValue(index);
|
||||
remove(index);
|
||||
return (V) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkKeyNonNull(K key) {
|
||||
if (key == null) {
|
||||
throw new UnsupportedOperationException("null not supported as key!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specific index and returns the index of the next element. This can
|
||||
* be a different value if graph compression was triggered.
|
||||
*/
|
||||
private int remove(int indexToRemove) {
|
||||
int index = indexToRemove;
|
||||
int entriesAfterIndex = totalEntries - index - 1;
|
||||
int result = index + 1;
|
||||
|
||||
// Without hash array, compress immediately.
|
||||
if (entriesAfterIndex <= COMPRESS_IMMEDIATE_CAPACITY && !hasHashArray()) {
|
||||
while (index < totalEntries - 1) {
|
||||
setKey(index, getKey(index + 1));
|
||||
setRawValue(index, getRawValue(index + 1));
|
||||
index++;
|
||||
}
|
||||
result--;
|
||||
}
|
||||
|
||||
setKey(index, null);
|
||||
setRawValue(index, null);
|
||||
if (index == totalEntries - 1) {
|
||||
// Make sure last element is always non-null.
|
||||
totalEntries--;
|
||||
while (index > 0 && getKey(index - 1) == null) {
|
||||
totalEntries--;
|
||||
deletedEntries--;
|
||||
index--;
|
||||
}
|
||||
} else {
|
||||
deletedEntries++;
|
||||
result = maybeCompress(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private abstract class SparseMapIterator<E> implements Iterator<E> {
|
||||
|
||||
protected int current;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current < totalEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (hasHashArray()) {
|
||||
EconomicMapImpl.this.findAndRemoveHash(getKey(current - 1));
|
||||
}
|
||||
current = EconomicMapImpl.this.remove(current - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<V> getValues() {
|
||||
return new Iterable<V>() {
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return new SparseMapIterator<V>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V next() {
|
||||
Object result;
|
||||
while (true) {
|
||||
result = getValue(current);
|
||||
if (result == null && getKey(current) == null) {
|
||||
// values can be null, double-check if key is also null
|
||||
current++;
|
||||
} else {
|
||||
current++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (V) result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCursor<K, V> getEntries() {
|
||||
return new MapCursor<K, V>() {
|
||||
int current = -1;
|
||||
|
||||
@Override
|
||||
public boolean advance() {
|
||||
current++;
|
||||
if (current >= totalEntries) {
|
||||
return false;
|
||||
} else {
|
||||
while (EconomicMapImpl.this.getKey(current) == null) {
|
||||
// Skip over null entries
|
||||
current++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public K getKey() {
|
||||
return (K) EconomicMapImpl.this.getKey(current);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V getValue() {
|
||||
return (V) EconomicMapImpl.this.getValue(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (hasHashArray()) {
|
||||
EconomicMapImpl.this.findAndRemoveHash(EconomicMapImpl.this.getKey(current));
|
||||
}
|
||||
current = EconomicMapImpl.this.remove(current) - 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
||||
for (int i = 0; i < totalEntries; i++) {
|
||||
Object entryKey = getKey(i);
|
||||
if (entryKey != null) {
|
||||
Object newValue = function.apply((K) entryKey, (V) getValue(i));
|
||||
setValue(i, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object getKey(int index) {
|
||||
return entries[index << 1];
|
||||
}
|
||||
|
||||
private void setKey(int index, Object newValue) {
|
||||
entries[index << 1] = newValue;
|
||||
}
|
||||
|
||||
private void setValue(int index, Object newValue) {
|
||||
Object oldValue = getRawValue(index);
|
||||
if (oldValue instanceof CollisionLink) {
|
||||
CollisionLink collisionLink = (CollisionLink) oldValue;
|
||||
setRawValue(index, new CollisionLink(newValue, collisionLink.next));
|
||||
} else {
|
||||
setRawValue(index, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRawValue(int index, Object newValue) {
|
||||
entries[(index << 1) + 1] = newValue;
|
||||
}
|
||||
|
||||
private Object getRawValue(int index) {
|
||||
return entries[(index << 1) + 1];
|
||||
}
|
||||
|
||||
private Object getValue(int index) {
|
||||
Object object = getRawValue(index);
|
||||
if (object instanceof CollisionLink) {
|
||||
return ((CollisionLink) object).value;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
private final boolean isSet;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(isSet ? "set(size=" : "map(size=").append(size()).append(", {");
|
||||
String sep = "";
|
||||
MapCursor<K, V> cursor = getEntries();
|
||||
while (cursor.advance()) {
|
||||
builder.append(sep);
|
||||
if (isSet) {
|
||||
builder.append(cursor.getKey());
|
||||
} else {
|
||||
builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append(")");
|
||||
}
|
||||
sep = ",";
|
||||
}
|
||||
builder.append("})");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return new SparseMapIterator<K>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public K next() {
|
||||
Object result;
|
||||
while ((result = getKey(current++)) == null) {
|
||||
// skip null entries
|
||||
}
|
||||
return (K) result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(K element) {
|
||||
return containsKey(element);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean add(K element) {
|
||||
return put(element, (V) element) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K element) {
|
||||
removeKey(element);
|
||||
}
|
||||
}
|
||||
@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Memory efficient set data structure.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface EconomicSet<E> extends UnmodifiableEconomicSet<E> {
|
||||
|
||||
/**
|
||||
* Adds {@code element} to this set if it is not already present.
|
||||
*
|
||||
* @return {@code true} if this set did not already contain {@code element}.
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean add(E element);
|
||||
|
||||
/**
|
||||
* Removes {@code element} from this set if it is present. This set will not contain
|
||||
* {@code element} once the call returns.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
void remove(E element);
|
||||
|
||||
/**
|
||||
* Removes all of the elements from this set. The set will be empty after this call returns.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Adds all of the elements in {@code other} to this set if they're not already present.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void addAll(EconomicSet<E> other) {
|
||||
addAll(other.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements in {@code values} to this set if they're not already present.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void addAll(Iterable<E> values) {
|
||||
addAll(values.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements enumerated by {@code iterator} to this set if they're not already
|
||||
* present.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void addAll(Iterator<E> iterator) {
|
||||
while (iterator.hasNext()) {
|
||||
add(iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from this set all of its elements that are contained in {@code other}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void removeAll(EconomicSet<E> other) {
|
||||
removeAll(other.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from this set all of its elements that are contained in {@code values}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void removeAll(Iterable<E> values) {
|
||||
removeAll(values.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from this set all of its elements that are enumerated by {@code iterator}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void removeAll(Iterator<E> iterator) {
|
||||
while (iterator.hasNext()) {
|
||||
remove(iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from this set all of its elements that are not contained in {@code other}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default void retainAll(EconomicSet<E> other) {
|
||||
Iterator<E> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
E key = iterator.next();
|
||||
if (!other.contains(key)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements with the
|
||||
* default {@link Equivalence#DEFAULT} comparison strategy.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create() {
|
||||
return EconomicSet.create(Equivalence.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create(Equivalence strategy) {
|
||||
return EconomicMapImpl.create(strategy, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements with the
|
||||
* default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
|
||||
* specified collection.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create(int initialCapacity) {
|
||||
return EconomicSet.create(Equivalence.DEFAULT, initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements with the
|
||||
* default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
|
||||
* specified collection.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create(UnmodifiableEconomicSet<E> c) {
|
||||
return EconomicSet.create(Equivalence.DEFAULT, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements and
|
||||
* initializes with the given capacity.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create(Equivalence strategy, int initialCapacity) {
|
||||
return EconomicMapImpl.create(strategy, initialCapacity, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set guaranteeing insertion order when iterating over its elements and inserts
|
||||
* all elements of the specified collection.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
static <E> EconomicSet<E> create(Equivalence strategy, UnmodifiableEconomicSet<E> c) {
|
||||
return EconomicMapImpl.create(strategy, c, true);
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
/**
|
||||
* Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT},
|
||||
* {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public abstract class Equivalence {
|
||||
|
||||
/**
|
||||
* Default equivalence calling {@link #equals(Object)} to check equality and {@link #hashCode()}
|
||||
* for obtaining hash values. Do not change the logic of this class as it may be inlined in
|
||||
* other places.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static final Equivalence DEFAULT = new Equivalence() {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object a, Object b) {
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return o.hashCode();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining
|
||||
* hash values. Do not change the logic of this class as it may be inlined in other places.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static final Equivalence IDENTITY = new Equivalence() {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object a, Object b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return o.hashCode();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Identity equivalence using {@code ==} to check equality and
|
||||
* {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of
|
||||
* this class as it may be inlined in other places.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object a, Object b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return System.identityHashCode(o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Subclass for creating custom equivalence definitions.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
protected Equivalence() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the non-{@code null} arguments are equal to each other and
|
||||
* {@code false} otherwise.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public abstract boolean equals(Object a, Object b);
|
||||
|
||||
/**
|
||||
* Returns the hash code of a non-{@code null} argument {@code o}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public abstract int hashCode(Object o);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
/**
|
||||
* Cursor to iterate over a mutable map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface MapCursor<K, V> extends UnmodifiableMapCursor<K, V> {
|
||||
/**
|
||||
* Remove the current entry from the map. May only be called once. After calling
|
||||
* {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on
|
||||
* the current entry.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
void remove();
|
||||
}
|
||||
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Utility class representing a pair of values.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final class Pair<L, R> {
|
||||
|
||||
private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);
|
||||
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
/**
|
||||
* Returns an empty pair.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <L, R> Pair<L, R> empty() {
|
||||
return (Pair<L, R>) EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pair with its left value being {@code left}, or returns an empty pair if
|
||||
* {@code left} is null.
|
||||
*
|
||||
* @return the constructed pair or an empty pair if {@code left} is null.
|
||||
* @since 19.0
|
||||
*/
|
||||
public static <L, R> Pair<L, R> createLeft(L left) {
|
||||
if (left == null) {
|
||||
return empty();
|
||||
} else {
|
||||
return new Pair<>(left, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pair with its right value being {@code right}, or returns an empty pair if
|
||||
* {@code right} is null.
|
||||
*
|
||||
* @return the constructed pair or an empty pair if {@code right} is null.
|
||||
* @since 19.0
|
||||
*/
|
||||
public static <L, R> Pair<L, R> createRight(R right) {
|
||||
if (right == null) {
|
||||
return empty();
|
||||
} else {
|
||||
return new Pair<>(null, right);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pair with its left value being {@code left}, and its right value being
|
||||
* {@code right}, or returns an empty pair if both inputs are null.
|
||||
*
|
||||
* @return the constructed pair or an empty pair if both inputs are null.
|
||||
* @since 19.0
|
||||
*/
|
||||
public static <L, R> Pair<L, R> create(L left, R right) {
|
||||
if (right == null && left == null) {
|
||||
return empty();
|
||||
} else {
|
||||
return new Pair<>(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
private Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the left value of this pair.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the right value of this pair.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(left) + 31 * Objects.hashCode(right);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof Pair) {
|
||||
Pair<L, R> pair = (Pair<L, R>) obj;
|
||||
return Objects.equals(left, pair.left) && Objects.equals(right, pair.right);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("(%s, %s)", left, right);
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
/**
|
||||
* Unmodifiable memory efficient map. See {@link EconomicMap} for the underlying data structure and
|
||||
* its properties.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface UnmodifiableEconomicMap<K, V> {
|
||||
|
||||
/**
|
||||
* Returns the value to which {@code key} is mapped, or {@code null} if this map contains no
|
||||
* mapping for {@code key}. The {@code key} must not be {@code null}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
V get(K key);
|
||||
|
||||
/**
|
||||
* Returns the value to which {@code key} is mapped, or {@code defaultValue} if this map
|
||||
* contains no mapping for {@code key}. The {@code key} must not be {@code null}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
default V get(K key, V defaultValue) {
|
||||
V v = get(key);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains a mapping for {@code key}. Returns always
|
||||
* {@code false} if the {@code key} is {@code null}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean containsKey(K key);
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings in this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains no key-value mappings.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns a {@link Iterable} view of the values contained in this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
Iterable<V> getValues();
|
||||
|
||||
/**
|
||||
* Returns a {@link Iterable} view of the keys contained in this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
Iterable<K> getKeys();
|
||||
|
||||
/**
|
||||
* Returns a {@link UnmodifiableMapCursor} view of the mappings contained in this map.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnmodifiableMapCursor<K, V> getEntries();
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
/**
|
||||
* Unmodifiable memory efficient set data structure.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface UnmodifiableEconomicSet<E> extends Iterable<E> {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this set contains a mapping for the {@code element}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean contains(E element);
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this set.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this set contains no elements.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Stores all of the elements in this set into {@code target}. An
|
||||
* {@link UnsupportedOperationException} will be thrown if the length of {@code target} does not
|
||||
* match the size of this set.
|
||||
*
|
||||
* @return an array containing all the elements in this set.
|
||||
* @throws UnsupportedOperationException if the length of {@code target} does not equal the size
|
||||
* of this set.
|
||||
* @since 19.0
|
||||
*/
|
||||
default E[] toArray(E[] target) {
|
||||
if (target.length != size()) {
|
||||
throw new UnsupportedOperationException("Length of target array must equal the size of the set.");
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (E element : this) {
|
||||
target[index++] = element;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
|
||||
/**
|
||||
* Cursor to iterate over a map without changing its contents.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface UnmodifiableMapCursor<K, V> {
|
||||
/**
|
||||
* Advances to the next entry.
|
||||
*
|
||||
* @return {@code true} if a next entry exists, {@code false} if there is no next entry.
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean advance();
|
||||
|
||||
/**
|
||||
* The key of the current entry.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
K getKey();
|
||||
|
||||
/**
|
||||
* The value of the current entry.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
V getValue();
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
@ApiInfo(
|
||||
group="GraalVM SDK"
|
||||
)
|
||||
*/
|
||||
/**
|
||||
* The GraalVM SDK collections package contains memory efficient data structures.
|
||||
*
|
||||
* @see jdk.internal.vm.compiler.collections.EconomicMap
|
||||
* @see jdk.internal.vm.compiler.collections.EconomicSet
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.collections;
|
||||
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.libgraal;
|
||||
|
||||
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotSpeculationLog;
|
||||
import jdk.vm.ci.services.Services;
|
||||
|
||||
/**
|
||||
* JDK13+ version of {@code LibGraal}.
|
||||
*/
|
||||
public class LibGraal {
|
||||
|
||||
static {
|
||||
// Initialize JVMCI to ensure JVMCI opens its packages to Graal.
|
||||
Services.initializeJVMCI();
|
||||
}
|
||||
|
||||
public static boolean isAvailable() {
|
||||
return inLibGraal() || theIsolate != 0L;
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean inLibGraal() {
|
||||
return Services.IS_IN_NATIVE_IMAGE;
|
||||
}
|
||||
|
||||
public static void registerNativeMethods(Class<?> clazz) {
|
||||
if (clazz.isPrimitive()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (inLibGraal() || !isAvailable()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
runtime().registerNativeMethods(clazz);
|
||||
}
|
||||
|
||||
public static long translate(Object obj) {
|
||||
if (!isAvailable()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
|
||||
throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
|
||||
}
|
||||
return runtime().translate(obj);
|
||||
}
|
||||
|
||||
public static <T> T unhand(Class<T> type, long handle) {
|
||||
if (!isAvailable()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
|
||||
throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
|
||||
}
|
||||
return runtime().unhand(type, handle);
|
||||
}
|
||||
|
||||
private static long initializeLibgraal() {
|
||||
try {
|
||||
long[] javaVMInfo = runtime().registerNativeMethods(LibGraalScope.class);
|
||||
return javaVMInfo[1];
|
||||
} catch (UnsupportedOperationException e) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
static final long theIsolate = Services.IS_BUILDING_NATIVE_IMAGE ? 0L : initializeLibgraal();
|
||||
|
||||
static boolean isCurrentThreadAttached() {
|
||||
return runtime().isCurrentThreadAttached();
|
||||
}
|
||||
|
||||
public static boolean attachCurrentThread(boolean isDaemon, long[] isolate) {
|
||||
if (isolate != null) {
|
||||
isolate[0] = LibGraal.theIsolate;
|
||||
}
|
||||
return runtime().attachCurrentThread(isDaemon);
|
||||
}
|
||||
|
||||
public static boolean detachCurrentThread(boolean release) {
|
||||
runtime().detachCurrentThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static long getFailedSpeculationsAddress(HotSpotSpeculationLog log) {
|
||||
return log.getFailedSpeculationsAddress();
|
||||
}
|
||||
}
|
||||
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.libgraal;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Represents a single libgraal isolate. All {@link LibGraalObject}s have a {@link LibGraalIsolate}
|
||||
* context.
|
||||
*/
|
||||
public final class LibGraalIsolate {
|
||||
|
||||
final long address;
|
||||
|
||||
private static final Map<Long, LibGraalIsolate> isolates = new HashMap<>();
|
||||
|
||||
static synchronized LibGraalIsolate forAddress(long isolateAddress) {
|
||||
return isolates.computeIfAbsent(isolateAddress, a -> new LibGraalIsolate(a));
|
||||
}
|
||||
|
||||
private LibGraalIsolate(long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the isolate associated with the current thread. The current thread must be in an
|
||||
* {@linkplain LibGraalScope opened} scope.
|
||||
*
|
||||
* @throws IllegalStateException if the current thread is not attached to libgraal
|
||||
*/
|
||||
public static LibGraalIsolate current() {
|
||||
return LibGraalScope.current().getIsolate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value corresponding to {@code key} from a key-value store of singleton objects. If
|
||||
* no value corresponding to {@code key} currently exists, then it is computed with
|
||||
* {@code supplier} and inserted in the store.
|
||||
*
|
||||
* This is used to obtain objects whose lifetime is bound to the isolate represented by this
|
||||
* object.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized <T> T getSingleton(Class<T> key, Supplier<T> supplier) {
|
||||
// Cannot use HahsMap.computeIfAbsent as it will throw a ConcurrentModificationException
|
||||
// if supplier recurses here to compute another singleton.
|
||||
if (!singletons.containsKey(key)) {
|
||||
singletons.put(key, supplier.get());
|
||||
}
|
||||
return (T) singletons.get(key);
|
||||
}
|
||||
|
||||
private final Map<Class<?>, Object> singletons = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Strong references to the {@link WeakReference} objects.
|
||||
*/
|
||||
private final Set<LibGraalIsolate.Cleaner> cleaners = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
void register(LibGraalObject obj, long handle) {
|
||||
cleanHandles();
|
||||
Cleaner cref = new Cleaner(cleanersQueue, obj, handle);
|
||||
cleaners.add(cref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes {@link #cleanersQueue} to release any handles whose {@link LibGraalObject} objects
|
||||
* are now unreachable.
|
||||
*/
|
||||
private void cleanHandles() {
|
||||
Cleaner cleaner;
|
||||
while ((cleaner = (Cleaner) cleanersQueue.poll()) != null) {
|
||||
cleaners.remove(cleaner);
|
||||
if (!cleaner.clean()) {
|
||||
new Exception(String.format("Error releasing handle %d in isolate 0x%x", cleaner.handle, address)).printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue into which a {@link Cleaner} is enqueued when its {@link LibGraalObject} referent
|
||||
* becomes unreachable.
|
||||
*/
|
||||
private final ReferenceQueue<LibGraalObject> cleanersQueue = new ReferenceQueue<>();
|
||||
|
||||
private static final class Cleaner extends WeakReference<LibGraalObject> {
|
||||
private final long handle;
|
||||
|
||||
Cleaner(ReferenceQueue<LibGraalObject> cleanersQueue, LibGraalObject referent, long handle) {
|
||||
super(referent, cleanersQueue);
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
boolean clean() {
|
||||
return LibGraalObject.releaseHandle(LibGraalScope.getIsolateThread(), handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that the {@code JavaVM} associated with {@code isolate} has been destroyed. All
|
||||
* subsequent accesses to objects in the isolate will throw an {@link IllegalArgumentException}.
|
||||
*/
|
||||
static synchronized void remove(LibGraalIsolate isolate) {
|
||||
isolate.destroyed = true;
|
||||
LibGraalIsolate removed = isolates.remove(isolate.address);
|
||||
assert removed == isolate : "isolate already removed or overwritten: " + isolate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[0x%x]", getClass().getSimpleName(), address);
|
||||
}
|
||||
|
||||
private boolean destroyed;
|
||||
|
||||
public boolean isValid() {
|
||||
return !destroyed;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.libgraal;
|
||||
|
||||
/**
|
||||
* Encapsulates a handle to an object in a libgraal isolate where the object's lifetime is bound to
|
||||
* the lifetime of the {@link LibGraalObject} instance. At some point after a {@link LibGraalObject}
|
||||
* is garbage collected, a call is made to release the handle, allowing the libgraal object to be
|
||||
* collected.
|
||||
*/
|
||||
public class LibGraalObject {
|
||||
|
||||
static {
|
||||
if (LibGraal.isAvailable()) {
|
||||
LibGraal.registerNativeMethods(LibGraalObject.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle to an object in {@link #isolate}.
|
||||
*/
|
||||
private final long handle;
|
||||
|
||||
/**
|
||||
* The libgraal isolate containing {@link #handle}.
|
||||
*/
|
||||
private final LibGraalIsolate isolate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LibGraalObject}.
|
||||
*
|
||||
* @param handle handle to an object in a libgraal isolate
|
||||
*/
|
||||
protected LibGraalObject(long handle) {
|
||||
this.handle = handle;
|
||||
isolate = LibGraalScope.current().getIsolate();
|
||||
isolate.register(this, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw JNI handle wrapped by this object.
|
||||
*
|
||||
* @throw {@link IllegalArgumentException} if the isolate context for the handle has destroyed.
|
||||
*/
|
||||
public long getHandle() {
|
||||
if (!isolate.isValid()) {
|
||||
throw new IllegalArgumentException(toString());
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases {@code handle} in the isolate denoted by {@code isolateThreadId}.
|
||||
*
|
||||
* @return {@code false} if {@code} is not a valid handle in the isolate
|
||||
*/
|
||||
// Implementation:
|
||||
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.releaseHandle
|
||||
static native boolean releaseHandle(long isolateThreadId, long handle);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getClass().getSimpleName();
|
||||
Class<?> outer = getClass().getDeclaringClass();
|
||||
while (outer != null) {
|
||||
name = outer.getSimpleName() + '.' + name;
|
||||
outer = outer.getDeclaringClass();
|
||||
}
|
||||
return String.format("%s[%d]", name, handle);
|
||||
}
|
||||
}
|
||||
@ -1,306 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.libgraal;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope() Opening} a scope ensures
|
||||
* the current thread is attached to libgraal and {@linkplain #close() closing} the outer most scope
|
||||
* detaches the current thread.
|
||||
*/
|
||||
public final class LibGraalScope implements AutoCloseable {
|
||||
|
||||
static final ThreadLocal<LibGraalScope> currentScope = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Shared state between a thread's nested scopes.
|
||||
*/
|
||||
static class Shared {
|
||||
final DetachAction detachAction;
|
||||
final LibGraalIsolate isolate;
|
||||
final long isolateThread;
|
||||
|
||||
Shared(DetachAction detachAction, LibGraalIsolate isolate, long isolateThread) {
|
||||
this.detachAction = detachAction;
|
||||
this.isolate = isolate;
|
||||
this.isolateThread = isolateThread;
|
||||
}
|
||||
}
|
||||
|
||||
private final LibGraalScope parent;
|
||||
private final Shared shared;
|
||||
|
||||
/**
|
||||
* Gets the current scope.
|
||||
*
|
||||
* @throws IllegalStateException if the current thread is not in an {@linkplain #LibGraalScope()
|
||||
* opened} scope
|
||||
*/
|
||||
public static LibGraalScope current() {
|
||||
LibGraalScope scope = currentScope.get();
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("Not in an " + LibGraalScope.class.getSimpleName());
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the isolate thread associated with the current thread. The current thread must be in an
|
||||
* {@linkplain #LibGraalScope() opened} scope.
|
||||
*
|
||||
* @returns a value that can be used for the IsolateThreadContext argument of a {@code native}
|
||||
* method {@link LibGraal#registerNativeMethods linked} to a CEntryPoint function in
|
||||
* libgraal
|
||||
* @throws IllegalStateException if the current thread is not attached to libgraal
|
||||
*/
|
||||
public static long getIsolateThread() {
|
||||
return current().shared.isolateThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes the detach action to perform when closing a {@link LibGraalScope}.
|
||||
*/
|
||||
public enum DetachAction {
|
||||
/**
|
||||
* Detach the thread from its libgraal isolate.
|
||||
*/
|
||||
DETACH,
|
||||
|
||||
/**
|
||||
* Detach the thread from its libgraal isolate and the associated {@code JVMCIRuntime}.
|
||||
*/
|
||||
DETACH_RUNTIME,
|
||||
|
||||
/**
|
||||
* Detach the thread from its libgraal isolate and the associated {@code JVMCIRuntime}. If
|
||||
* the VM supports releasing the {@code JavaVM} associated with {@code JVMCIRuntime}s and
|
||||
* this is the last thread attached to its {@code JVMCIRuntime}, then the
|
||||
* {@code JVMCIRuntime} destroys its {@code JavaVM} instance.
|
||||
*/
|
||||
DETACH_RUNTIME_AND_RELEASE
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for calling {@link #LibGraalScope(DetachAction)} with an argument of
|
||||
* {@link DetachAction#DETACH_RUNTIME}.
|
||||
*/
|
||||
public LibGraalScope() {
|
||||
this(DetachAction.DETACH_RUNTIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters a scope for making calls into libgraal. If there is no existing libgraal scope for the
|
||||
* current thread, the current thread is attached to libgraal. When the outer most scope is
|
||||
* closed, the current thread is detached from libgraal.
|
||||
*
|
||||
* This must be used in a try-with-resources statement.
|
||||
*
|
||||
* This cannot be called from {@linkplain LibGraal#inLibGraal() within} libgraal.
|
||||
*
|
||||
* @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
|
||||
* or {@link LibGraal#inLibGraal()} returns true
|
||||
*/
|
||||
public LibGraalScope(DetachAction detachAction) {
|
||||
if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
parent = currentScope.get();
|
||||
if (parent == null) {
|
||||
long[] isolateBox = {0};
|
||||
boolean firstAttach = LibGraal.attachCurrentThread(false, isolateBox);
|
||||
long isolateAddress = isolateBox[0];
|
||||
LibGraalIsolate isolate = LibGraalIsolate.forAddress(isolateAddress);
|
||||
long isolateThread = getIsolateThreadIn(isolateAddress);
|
||||
shared = new Shared(firstAttach ? detachAction : null, isolate, isolateThread);
|
||||
} else {
|
||||
shared = parent.shared;
|
||||
}
|
||||
currentScope.set(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters a scope for making calls into an existing libgraal isolate. If there is no existing
|
||||
* libgraal scope for the current thread, the current thread is attached to libgraal. When the
|
||||
* outer most scope is closed, the current thread is detached from libgraal.
|
||||
*
|
||||
* This must be used in a try-with-resources statement.
|
||||
*
|
||||
* This cannot be called from {@linkplain LibGraal#inLibGraal() within} libgraal.
|
||||
*
|
||||
* @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
|
||||
* or {@link LibGraal#inLibGraal()} returns true
|
||||
*/
|
||||
public LibGraalScope(long isolateAddress) {
|
||||
if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
parent = currentScope.get();
|
||||
if (parent == null) {
|
||||
long isolateThread = getIsolateThreadIn(isolateAddress);
|
||||
boolean alreadyAttached;
|
||||
if (isolateThread == 0L) {
|
||||
alreadyAttached = false;
|
||||
isolateThread = attachThreadTo(isolateAddress);
|
||||
} else {
|
||||
alreadyAttached = true;
|
||||
}
|
||||
LibGraalIsolate isolate = LibGraalIsolate.forAddress(isolateAddress);
|
||||
shared = new Shared(alreadyAttached ? null : DetachAction.DETACH, isolate, isolateThread);
|
||||
} else {
|
||||
shared = parent.shared;
|
||||
}
|
||||
currentScope.set(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the current thread to the isolate at {@code isolateAddress}.
|
||||
*
|
||||
* @return the address of the attached IsolateThread
|
||||
*/
|
||||
// Implementation:
|
||||
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.attachThreadTo
|
||||
static native long attachThreadTo(long isolateAddress);
|
||||
|
||||
/**
|
||||
* Detaches the current thread from the isolate at {@code isolateAddress}.
|
||||
*/
|
||||
// Implementation:
|
||||
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.detachThreadFrom
|
||||
static native void detachThreadFrom(long isolateThreadAddress);
|
||||
|
||||
/**
|
||||
* Gets the isolate thread for the current thread in the isolate at {@code isolateAddress}.
|
||||
*
|
||||
* @return 0L if the current thread is not attached to the isolate at {@code isolateAddress}
|
||||
*/
|
||||
// Implementation:
|
||||
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.getIsolateThreadIn
|
||||
@SuppressWarnings("unused")
|
||||
static native long getIsolateThreadIn(long isolateAddress);
|
||||
|
||||
/**
|
||||
* Gets the isolate associated with this scope.
|
||||
*/
|
||||
public LibGraalIsolate getIsolate() {
|
||||
return shared.isolate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the isolate thread associated with this scope.
|
||||
*/
|
||||
public long getIsolateThreadAddress() {
|
||||
return shared.isolateThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (parent == null && shared.detachAction != null) {
|
||||
if (shared.detachAction == DetachAction.DETACH) {
|
||||
detachThreadFrom(shared.isolateThread);
|
||||
} else {
|
||||
boolean isolateDestroyed = LibGraal.detachCurrentThread(shared.detachAction == DetachAction.DETACH_RUNTIME_AND_RELEASE);
|
||||
if (isolateDestroyed) {
|
||||
LibGraalIsolate.remove(shared.isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
currentScope.set(parent);
|
||||
}
|
||||
|
||||
// Shared support for the LibGraal overlays
|
||||
|
||||
/**
|
||||
* Convenience function for wrapping varargs into an array for use in calls to
|
||||
* {@link #method(Class, String, Class[][])}.
|
||||
*/
|
||||
static Class<?>[] sig(Class<?>... types) {
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method in {@code declaringClass} with the unique name {@code name}.
|
||||
*
|
||||
* @param sigs the signatures the method may have
|
||||
*/
|
||||
static Method method(Class<?> declaringClass, String name, Class<?>[]... sigs) {
|
||||
if (sigs.length == 1 || sigs.length == 0) {
|
||||
try {
|
||||
Class<?>[] sig = sigs.length == 1 ? sigs[0] : new Class<?>[0];
|
||||
return declaringClass.getDeclaredMethod(name, sig);
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
throw (NoSuchMethodError) new NoSuchMethodError(name).initCause(e);
|
||||
}
|
||||
}
|
||||
Method match = null;
|
||||
for (Method m : declaringClass.getDeclaredMethods()) {
|
||||
if (m.getName().equals(name)) {
|
||||
if (match != null) {
|
||||
throw new InternalError(String.format("Expected single method named %s, found %s and %s",
|
||||
name, match, m));
|
||||
}
|
||||
match = m;
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NoSuchMethodError("Cannot find method " + name + " in " + declaringClass.getName());
|
||||
}
|
||||
Class<?>[] parameterTypes = match.getParameterTypes();
|
||||
for (Class<?>[] sig : sigs) {
|
||||
if (Arrays.equals(parameterTypes, sig)) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodError(String.format("Unexpected signature for %s: %s", name, Arrays.toString(parameterTypes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method in {@code declaringClass} with the unique name {@code name} or {@code null}
|
||||
* if not found.
|
||||
*
|
||||
* @param sigs the signatures the method may have
|
||||
*/
|
||||
static Method methodOrNull(Class<?> declaringClass, String name, Class<?>[]... sigs) {
|
||||
try {
|
||||
return method(declaringClass, name, sigs);
|
||||
} catch (NoSuchMethodError e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method in {@code declaringClass} with the unique name {@code name} or {@code null}
|
||||
* if {@code guard == null}.
|
||||
*
|
||||
* @param sigs the signatures the method may have
|
||||
*/
|
||||
static Method methodIf(Object guard, Class<?> declaringClass, String name, Class<?>[]... sigs) {
|
||||
if (guard == null) {
|
||||
return null;
|
||||
}
|
||||
return method(declaringClass, name, sigs);
|
||||
}
|
||||
}
|
||||
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.libgraal;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Facilities for encoding/decoding a set of options to/from a byte array.
|
||||
*/
|
||||
public final class OptionsEncoder {
|
||||
|
||||
private OptionsEncoder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if {@code value} is supported by {@link #encode(Map)}.
|
||||
*/
|
||||
public static boolean isValueSupported(Object value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> valueClass = value.getClass();
|
||||
return valueClass == Boolean.class ||
|
||||
valueClass == Byte.class ||
|
||||
valueClass == Short.class ||
|
||||
valueClass == Character.class ||
|
||||
valueClass == Integer.class ||
|
||||
valueClass == Long.class ||
|
||||
valueClass == Float.class ||
|
||||
valueClass == Double.class ||
|
||||
valueClass == String.class ||
|
||||
value.getClass().isEnum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes {@code options} into a byte array.
|
||||
*
|
||||
* @throws IllegalArgumentException if any value in {@code options} is not
|
||||
* {@linkplain #isValueSupported(Object) supported}
|
||||
*/
|
||||
public static byte[] encode(final Map<String, Object> options) {
|
||||
try (ByteArrayOutputStream baout = new ByteArrayOutputStream()) {
|
||||
try (DataOutputStream out = new DataOutputStream(baout)) {
|
||||
out.writeInt(options.size());
|
||||
for (Map.Entry<String, Object> e : options.entrySet()) {
|
||||
final String key = e.getKey();
|
||||
out.writeUTF(key);
|
||||
final Object value = e.getValue();
|
||||
final Class<?> valueClz = value.getClass();
|
||||
if (valueClz == Boolean.class) {
|
||||
out.writeByte('Z');
|
||||
out.writeBoolean((Boolean) value);
|
||||
} else if (valueClz == Byte.class) {
|
||||
out.writeByte('B');
|
||||
out.writeByte((Byte) value);
|
||||
} else if (valueClz == Short.class) {
|
||||
out.writeByte('S');
|
||||
out.writeShort((Short) value);
|
||||
} else if (valueClz == Character.class) {
|
||||
out.writeByte('C');
|
||||
out.writeChar((Character) value);
|
||||
} else if (valueClz == Integer.class) {
|
||||
out.writeByte('I');
|
||||
out.writeInt((Integer) value);
|
||||
} else if (valueClz == Long.class) {
|
||||
out.writeByte('J');
|
||||
out.writeLong((Long) value);
|
||||
} else if (valueClz == Float.class) {
|
||||
out.writeByte('F');
|
||||
out.writeFloat((Float) value);
|
||||
} else if (valueClz == Double.class) {
|
||||
out.writeByte('D');
|
||||
out.writeDouble((Double) value);
|
||||
} else if (valueClz == String.class) {
|
||||
out.writeByte('U');
|
||||
out.writeUTF((String) value);
|
||||
} else if (valueClz.isEnum()) {
|
||||
out.writeByte('U');
|
||||
out.writeUTF(((Enum<?>) value).name());
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Key: %s, Value: %s, Value type: %s", key, value, valueClz));
|
||||
}
|
||||
}
|
||||
}
|
||||
return baout.toByteArray();
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalArgumentException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes {@code input} into a name/value map.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code input} cannot be decoded
|
||||
*/
|
||||
public static Map<String, Object> decode(byte[] input) {
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(input))) {
|
||||
final int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final String key = in.readUTF();
|
||||
final Object value;
|
||||
final byte type = in.readByte();
|
||||
switch (type) {
|
||||
case 'Z':
|
||||
value = in.readBoolean();
|
||||
break;
|
||||
case 'B':
|
||||
value = in.readByte();
|
||||
break;
|
||||
case 'S':
|
||||
value = in.readShort();
|
||||
break;
|
||||
case 'C':
|
||||
value = in.readChar();
|
||||
break;
|
||||
case 'I':
|
||||
value = in.readInt();
|
||||
break;
|
||||
case 'J':
|
||||
value = in.readLong();
|
||||
break;
|
||||
case 'F':
|
||||
value = in.readFloat();
|
||||
break;
|
||||
case 'D':
|
||||
value = in.readDouble();
|
||||
break;
|
||||
case 'U':
|
||||
value = in.readUTF();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported value type: " + Integer.toHexString(type));
|
||||
}
|
||||
res.put(key, value);
|
||||
}
|
||||
if (in.available() != 0) {
|
||||
throw new IllegalArgumentException(in.available() + " undecoded bytes");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalArgumentException(ioe);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
/**
|
||||
* A machine-word-sized value that can be compared for equality.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface ComparableWord extends WordBase {
|
||||
|
||||
/**
|
||||
* Compares this word with the specified value.
|
||||
*
|
||||
* @param val value to which this word is to be compared.
|
||||
* @return {@code this == val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean equal(ComparableWord val);
|
||||
|
||||
/**
|
||||
* Compares this word with the specified value.
|
||||
*
|
||||
* @param val value to which this word is to be compared.
|
||||
* @return {@code this != val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean notEqual(ComparableWord val);
|
||||
}
|
||||
@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
// JaCoCo Exclude
|
||||
|
||||
/**
|
||||
* Marker interface for location identities. A different location identity of two memory accesses
|
||||
* guarantees that the two accesses do not interfere.
|
||||
* <p>
|
||||
* Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
|
||||
* comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
|
||||
* {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public abstract class LocationIdentity {
|
||||
|
||||
private static final class AnyLocationIdentity extends LocationIdentity {
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ANY_LOCATION";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InitLocationIdentity extends LocationIdentity {
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "INIT_LOCATION";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new location identity. Subclasses are responsible to provide proper implementations
|
||||
* of {@link #equals} and {@link #hashCode}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
protected LocationIdentity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the given location is the union of all possible mutable locations. A write to
|
||||
* such a location kill all reads from mutable locations and a read from this location is killed
|
||||
* by any write (except for initialization writes).
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
|
||||
|
||||
/**
|
||||
* Location only allowed to be used for writes. Indicates that a completely new memory location
|
||||
* is written. Kills no read. The previous value at the given location must be either
|
||||
* uninitialized or null. Writes to this location do not need a GC pre-barrier.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
|
||||
|
||||
/**
|
||||
* Indicates that the given location is the union of all possible mutable locations. A write to
|
||||
* such a location kill all reads from mutable locations and a read from this location is killed
|
||||
* by any write (except for initialization writes).
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static LocationIdentity any() {
|
||||
return ANY_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location only allowed to be used for writes. Indicates that a completely new memory location
|
||||
* is written. Kills no read. The previous value at the given location must be either
|
||||
* uninitialized or null. Writes to this location do not need a GC pre-barrier.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public static LocationIdentity init() {
|
||||
return INIT_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes a location is unchanging in all cases. Not that this is different than the Java
|
||||
* notion of final which only requires definite assignment.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public abstract boolean isImmutable();
|
||||
|
||||
/**
|
||||
* The inversion of {@link #isImmutable}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final boolean isMutable() {
|
||||
return !isImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this location identity is {@link #any}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final boolean isAny() {
|
||||
return this == ANY_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this location identity is {@link #init}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final boolean isInit() {
|
||||
return this == INIT_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this location identity is not {@link #any}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final boolean isSingle() {
|
||||
return this != ANY_LOCATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the memory slice denoted by this location identity may overlap with the
|
||||
* provided other location identity.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final boolean overlaps(LocationIdentity other) {
|
||||
return isAny() || other.isAny() || this.equals(other);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
/**
|
||||
* Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
|
||||
* necessarily all the memory access methods defined in {@link Pointer}).
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface PointerBase extends ComparableWord {
|
||||
|
||||
/**
|
||||
* Returns true if this pointer is the {@link WordFactory#nullPointer null pointer}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean isNull();
|
||||
|
||||
/**
|
||||
* Returns true if this pointer is not the {@link WordFactory#nullPointer null pointer}.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean isNonNull();
|
||||
}
|
||||
@ -1,385 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
/**
|
||||
* Represents a signed word-sized value.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface SignedWord extends ComparableWord {
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this + val)}.
|
||||
*
|
||||
* @param val value to be added to this Signed.
|
||||
* @return {@code this + val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord add(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this - val)}.
|
||||
*
|
||||
* @param val value to be subtracted from this Signed.
|
||||
* @return {@code this - val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord subtract(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this * val)}.
|
||||
*
|
||||
* @param val value to be multiplied by this Signed.
|
||||
* @return {@code this * val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord multiply(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this / val)}.
|
||||
*
|
||||
* @param val value by which this Signed is to be divided.
|
||||
* @return {@code this / val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedDivide(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this % val)}.
|
||||
*
|
||||
* @param val value by which this Signed is to be divided, and the remainder computed.
|
||||
* @return {@code this % val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedRemainder(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this << n)}.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this << n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord shiftLeft(UnsignedWord n);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this >> n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedShiftRight(UnsignedWord n);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
|
||||
* if and only if this and val are both negative.)
|
||||
*
|
||||
* @param val value to be AND'ed with this Signed.
|
||||
* @return {@code this & val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord and(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
|
||||
* if and only if either this or val is negative.)
|
||||
*
|
||||
* @param val value to be OR'ed with this Signed.
|
||||
* @return {@code this | val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord or(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
|
||||
* if and only if exactly one of this and val are negative.)
|
||||
*
|
||||
* @param val value to be XOR'ed with this Signed.
|
||||
* @return {@code this ^ val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord xor(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (~this)}. (This method returns a negative value if and
|
||||
* only if this Signed is non-negative.)
|
||||
*
|
||||
* @return {@code ~this}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord not();
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this == val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean equal(SignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this != val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean notEqual(SignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this < val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean lessThan(SignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this <= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean lessOrEqual(SignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this > val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean greaterThan(SignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this >= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean greaterOrEqual(SignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this + val)}.
|
||||
*
|
||||
* @param val value to be added to this Signed.
|
||||
* @return {@code this + val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord add(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this - val)}.
|
||||
*
|
||||
* @param val value to be subtracted from this Signed.
|
||||
* @return {@code this - val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord subtract(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this * val)}.
|
||||
*
|
||||
* @param val value to be multiplied by this Signed.
|
||||
* @return {@code this * val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord multiply(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this / val)}.
|
||||
*
|
||||
* @param val value by which this Signed is to be divided.
|
||||
* @return {@code this / val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedDivide(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this % val)}.
|
||||
*
|
||||
* @param val value by which this Signed is to be divided, and the remainder computed.
|
||||
* @return {@code this % val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedRemainder(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this << n)}.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this << n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord shiftLeft(int n);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this >> n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord signedShiftRight(int n);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
|
||||
* if and only if this and val are both negative.)
|
||||
*
|
||||
* @param val value to be AND'ed with this Signed.
|
||||
* @return {@code this & val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord and(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
|
||||
* if and only if either this or val is negative.)
|
||||
*
|
||||
* @param val value to be OR'ed with this Signed.
|
||||
* @return {@code this | val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord or(int val);
|
||||
|
||||
/**
|
||||
* Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
|
||||
* if and only if exactly one of this and val are negative.)
|
||||
*
|
||||
* @param val value to be XOR'ed with this Signed.
|
||||
* @return {@code this ^ val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
SignedWord xor(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this == val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean equal(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this != val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean notEqual(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this < val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean lessThan(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this <= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean lessOrEqual(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this > val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean greaterThan(int val);
|
||||
|
||||
/**
|
||||
* Compares this Signed with the specified value.
|
||||
*
|
||||
* @param val value to which this Signed is to be compared.
|
||||
* @return {@code this >= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean greaterOrEqual(int val);
|
||||
}
|
||||
@ -1,426 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
/**
|
||||
* Represents an unsigned word-sized value.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface UnsignedWord extends ComparableWord {
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this + val)}.
|
||||
*
|
||||
* @param val value to be added to this Unsigned.
|
||||
* @return {@code this + val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord add(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this - val)}.
|
||||
*
|
||||
* @param val value to be subtracted from this Unsigned.
|
||||
* @return {@code this - val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord subtract(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this * val)}.
|
||||
*
|
||||
* @param val value to be multiplied by this Unsigned.
|
||||
* @return {@code this * val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord multiply(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this / val)}.
|
||||
*
|
||||
* @param val value by which this Unsigned is to be divided.
|
||||
* @return {@code this / val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedDivide(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this % val)}.
|
||||
*
|
||||
* @param val value by which this Unsigned is to be divided, and the remainder computed.
|
||||
* @return {@code this % val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedRemainder(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this << n)}.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this << n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord shiftLeft(UnsignedWord n);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this >> n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedShiftRight(UnsignedWord n);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this & val)}.
|
||||
*
|
||||
* @param val value to be AND'ed with this Unsigned.
|
||||
* @return {@code this & val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord and(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this | val)}.
|
||||
*
|
||||
* @param val value to be OR'ed with this Unsigned.
|
||||
* @return {@code this | val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord or(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this ^ val)}.
|
||||
*
|
||||
* @param val value to be XOR'ed with this Unsigned.
|
||||
* @return {@code this ^ val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord xor(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (~this)}.
|
||||
*
|
||||
* @return {@code ~this}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord not();
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this == val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean equal(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this != val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean notEqual(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this < val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean belowThan(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this <= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean belowOrEqual(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this > val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean aboveThan(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this >= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean aboveOrEqual(UnsignedWord val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this + val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be added to this Unsigned.
|
||||
* @return {@code this + val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord add(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this - val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be subtracted from this Unsigned.
|
||||
* @return {@code this - val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord subtract(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this * val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be multiplied by this Unsigned.
|
||||
* @return {@code this * val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord multiply(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this / val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value by which this Unsigned is to be divided.
|
||||
* @return {@code this / val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedDivide(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this % val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value by which this Unsigned is to be divided, and the remainder computed.
|
||||
* @return {@code this % val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedRemainder(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this << n)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this << n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord shiftLeft(int n);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param n shift distance, in bits.
|
||||
* @return {@code this >> n}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord unsignedShiftRight(int n);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this & val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be AND'ed with this Unsigned.
|
||||
* @return {@code this & val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord and(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this | val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be OR'ed with this Unsigned.
|
||||
* @return {@code this | val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord or(int val);
|
||||
|
||||
/**
|
||||
* Returns a Unsigned whose value is {@code (this ^ val)}.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to be XOR'ed with this Unsigned.
|
||||
* @return {@code this ^ val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
UnsignedWord xor(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this == val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean equal(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this != val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean notEqual(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this < val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean belowThan(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this <= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean belowOrEqual(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this > val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean aboveThan(int val);
|
||||
|
||||
/**
|
||||
* Compares this Unsigned with the specified value.
|
||||
* <p>
|
||||
* Note that the right operand is a signed value, while the operation is performed unsigned.
|
||||
* Therefore, the result is only well-defined for positive right operands.
|
||||
*
|
||||
* @param val value to which this Unsigned is to be compared.
|
||||
* @return {@code this >= val}
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
boolean aboveOrEqual(int val);
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
/**
|
||||
* The root of the interface hierarchy for machine-word-sized values.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public interface WordBase {
|
||||
|
||||
/**
|
||||
* Conversion to a Java primitive value.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
long rawValue();
|
||||
|
||||
/**
|
||||
* This is deprecated because of the easy to mistype name collision between {@link #equals} and
|
||||
* the other word based equality routines. In general you should never be statically calling
|
||||
* this method anyway.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
boolean equals(Object o);
|
||||
}
|
||||
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
|
||||
import jdk.internal.vm.compiler.word.impl.WordBoxFactory;
|
||||
import jdk.internal.vm.compiler.word.impl.WordFactoryOpcode;
|
||||
import jdk.internal.vm.compiler.word.impl.WordFactoryOperation;
|
||||
|
||||
/**
|
||||
* Provides factory method to create machine-word-sized values.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
public final class WordFactory {
|
||||
|
||||
private WordFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The constant 0, i.e., the word with no bits set. There is no difference between a signed and
|
||||
* unsigned zero.
|
||||
*
|
||||
* @return the constant 0.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.ZERO)
|
||||
public static <T extends WordBase> T zero() {
|
||||
return WordBoxFactory.box(0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* The null pointer, i.e., the pointer with no bits set. There is no difference to a signed or
|
||||
* unsigned {@link #zero}.
|
||||
*
|
||||
* @return the null pointer.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.ZERO)
|
||||
public static <T extends PointerBase> T nullPointer() {
|
||||
return WordBoxFactory.box(0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe conversion from a Java long value to a Word. The parameter is treated as an unsigned
|
||||
* 64-bit value (in contrast to the semantics of a Java long).
|
||||
*
|
||||
* @param val a 64 bit unsigned value
|
||||
* @return the value cast to Word
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
|
||||
public static <T extends UnsignedWord> T unsigned(long val) {
|
||||
return WordBoxFactory.box(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe conversion from a Java long value to a {@link PointerBase pointer}. The parameter is
|
||||
* treated as an unsigned 64-bit value (in contrast to the semantics of a Java long).
|
||||
*
|
||||
* @param val a 64 bit unsigned value
|
||||
* @return the value cast to PointerBase
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
|
||||
public static <T extends PointerBase> T pointer(long val) {
|
||||
return WordBoxFactory.box(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe conversion from a Java int value to a Word. The parameter is treated as an unsigned
|
||||
* 32-bit value (in contrast to the semantics of a Java int).
|
||||
*
|
||||
* @param val a 32 bit unsigned value
|
||||
* @return the value cast to Word
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
|
||||
public static <T extends UnsignedWord> T unsigned(int val) {
|
||||
return WordBoxFactory.box(val & 0xffffffffL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe conversion from a Java long value to a Word. The parameter is treated as a signed
|
||||
* 64-bit value (unchanged semantics of a Java long).
|
||||
*
|
||||
* @param val a 64 bit signed value
|
||||
* @return the value cast to Word
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED)
|
||||
public static <T extends SignedWord> T signed(long val) {
|
||||
return WordBoxFactory.box(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe conversion from a Java int value to a Word. The parameter is treated as a signed
|
||||
* 32-bit value (unchanged semantics of a Java int).
|
||||
*
|
||||
* @param val a 32 bit signed value
|
||||
* @return the value cast to Word
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
@WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED)
|
||||
public static <T extends SignedWord> T signed(int val) {
|
||||
return WordBoxFactory.box(val);
|
||||
}
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word.impl;
|
||||
|
||||
import jdk.internal.vm.compiler.word.WordBase;
|
||||
|
||||
/**
|
||||
* Base class for a factory to create boxed {@link Word} instances. A concrete subclass must
|
||||
* initialize {@link #boxFactory}.
|
||||
*/
|
||||
public abstract class WordBoxFactory {
|
||||
|
||||
protected static WordBoxFactory boxFactory;
|
||||
|
||||
protected abstract <T extends WordBase> T boxImpl(long val);
|
||||
|
||||
public static <T extends WordBase> T box(long val) {
|
||||
return boxFactory.boxImpl(val);
|
||||
}
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word.impl;
|
||||
|
||||
/**
|
||||
* The canonical {@link WordFactoryOperation} represented by a method in a word type.
|
||||
*/
|
||||
public enum WordFactoryOpcode {
|
||||
ZERO,
|
||||
FROM_UNSIGNED,
|
||||
FROM_SIGNED,
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word.impl;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Links a method to a canonical operation represented by an {@link WordFactoryOpcode} val.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface WordFactoryOperation {
|
||||
WordFactoryOpcode opcode();
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
@ApiInfo(
|
||||
group="GraalVM SDK"
|
||||
)
|
||||
*/
|
||||
/**
|
||||
* This package provides a low-level mechanism to use machine-word-sized values in Java. The package
|
||||
* can only be used in the context of native images or Graal snippets.
|
||||
*
|
||||
* @since 19.0
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
package jdk.internal.vm.compiler.word;
|
||||
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.ParameterNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraalDirectives#blackhole}.
|
||||
*
|
||||
* There are two snippets for each kind:
|
||||
* <ul>
|
||||
* <li>blackhole<Kind>Snippet verifies that dead code elimination is prevented by the
|
||||
* blackhole directive.
|
||||
* <li><kind>Snippet verifies that dead code elimination does happen if the blackhole
|
||||
* directive is not there.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
public class BlackholeDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
private @interface BlackholeSnippet {
|
||||
boolean expectParameterUsage();
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = false)
|
||||
public static int booleanSnippet(int arg) {
|
||||
boolean b = arg > 3;
|
||||
if (b) {
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = true)
|
||||
public static int blackholeBooleanSnippet(int arg) {
|
||||
boolean b = arg > 3;
|
||||
GraalDirectives.blackhole(b);
|
||||
if (b) {
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoolean() {
|
||||
test("booleanSnippet", 5);
|
||||
test("blackholeBooleanSnippet", 5);
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = false)
|
||||
public static int intSnippet(int arg) {
|
||||
int x = 42 + arg;
|
||||
return x - arg;
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = true)
|
||||
public static int blackholeIntSnippet(int arg) {
|
||||
int x = 42 + arg;
|
||||
GraalDirectives.blackhole(x);
|
||||
return x - arg;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt() {
|
||||
test("intSnippet", 17);
|
||||
test("blackholeIntSnippet", 17);
|
||||
}
|
||||
|
||||
private static class Dummy {
|
||||
private int x = 42;
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = false)
|
||||
public static int objectSnippet(int arg) {
|
||||
Dummy obj = new Dummy();
|
||||
int ret = obj.x;
|
||||
obj.x = arg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@BlackholeSnippet(expectParameterUsage = true)
|
||||
public static int blackholeObjectSnippet(int arg) {
|
||||
Dummy obj = new Dummy();
|
||||
int ret = obj.x;
|
||||
obj.x = arg;
|
||||
GraalDirectives.blackhole(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObject() {
|
||||
test("objectSnippet", 37);
|
||||
test("blackholeObjectSnippet", 37);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);
|
||||
ParameterNode arg = graph.getParameter(0);
|
||||
if (snippet.expectParameterUsage()) {
|
||||
Assert.assertNotNull("couldn't find ParameterNode(0)", arg);
|
||||
Assert.assertFalse("expected usages of " + arg, arg.hasNoUsages());
|
||||
} else {
|
||||
Assert.assertTrue("expected no usages of ParameterNode", arg == null || arg.hasNoUsages());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
import org.graalvm.compiler.nodes.IfNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConstantProbablityBranchFoldingTest extends GraalCompilerTest {
|
||||
|
||||
public static int branchFoldingSnippet1() {
|
||||
if (GraalDirectives.injectBranchProbability(0.5, true)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public static int branchFoldingSnippet2() {
|
||||
if (GraalDirectives.injectBranchProbability(0.5, false)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyFolding1() {
|
||||
test("branchFoldingSnippet1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyFolding2() {
|
||||
test("branchFoldingSnippet2");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
|
||||
Assert.assertEquals("IfNode count", 0, ifNodes.count());
|
||||
}
|
||||
}
|
||||
@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.graph.Node;
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
import org.graalvm.compiler.nodes.IfNode;
|
||||
import org.graalvm.compiler.nodes.LoopBeginNode;
|
||||
import org.graalvm.compiler.nodes.ReturnNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Repeatable(AnchorSnippet.class)
|
||||
private @interface NodeCount {
|
||||
|
||||
Class<? extends Node> nodeClass();
|
||||
|
||||
int expectedCount();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
private @interface AnchorSnippet {
|
||||
NodeCount[] value();
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
|
||||
public static int verifyMergeSnippet(int arg) {
|
||||
if (arg > 5) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2)
|
||||
@NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
|
||||
public static int preventMergeSnippet(int arg) {
|
||||
if (arg > 5) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
return 1;
|
||||
} else {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
test("verifyMergeSnippet", 42);
|
||||
test("preventMergeSnippet", 42);
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
|
||||
public static int verifyDuplicateSnippet(int arg) {
|
||||
int ret;
|
||||
if (arg > 5) {
|
||||
ret = 17;
|
||||
} else {
|
||||
ret = arg;
|
||||
}
|
||||
return 42 / ret;
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
|
||||
@NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
|
||||
public static int preventDuplicateSnippet(int arg) {
|
||||
int ret;
|
||||
if (arg > 5) {
|
||||
ret = 17;
|
||||
} else {
|
||||
ret = arg;
|
||||
}
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
return 42 / ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicate() {
|
||||
// test("verifyDuplicateSnippet", 42);
|
||||
test("preventDuplicateSnippet", 42);
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0)
|
||||
public static int verifyFullUnrollSnippet(int arg) {
|
||||
int ret = arg;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ret = ret * 3 + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
|
||||
@NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
|
||||
public static int preventFullUnrollSnippet(int arg) {
|
||||
int ret = arg;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret = ret * 3 + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullUnroll() {
|
||||
test("verifyFullUnrollSnippet", 42);
|
||||
test("preventFullUnrollSnippet", 42);
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
|
||||
@NodeCount(nodeClass = IfNode.class, expectedCount = 4)
|
||||
public static void verifyPeelSnippet(int arg) {
|
||||
int ret = arg;
|
||||
while (ret > 1) {
|
||||
if (ret % 2 == 0) {
|
||||
ret /= 2;
|
||||
} else {
|
||||
ret = 3 * ret + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
|
||||
@NodeCount(nodeClass = IfNode.class, expectedCount = 2)
|
||||
public static void preventPeelSnippet(int arg) {
|
||||
int ret = arg;
|
||||
while (ret > 1) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
if (ret % 2 == 0) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret /= 2;
|
||||
} else {
|
||||
ret = 3 * ret + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeel() {
|
||||
test("preventPeelSnippet", 42);
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 2)
|
||||
public static void verifyUnswitchSnippet(int arg, boolean flag) {
|
||||
int ret = arg;
|
||||
while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) {
|
||||
if (flag) {
|
||||
ret = ret * 2 + 1;
|
||||
} else {
|
||||
ret = ret * 3 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
|
||||
@NodeCount(nodeClass = IfNode.class, expectedCount = 2)
|
||||
public static void preventUnswitchSnippet(int arg, boolean flag) {
|
||||
int ret = arg;
|
||||
while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) {
|
||||
if (flag) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret++;
|
||||
} else {
|
||||
ret += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnswitch() {
|
||||
test("verifyUnswitchSnippet", 0, false);
|
||||
test("preventUnswitchSnippet", 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning a ControlFlowAnchorNode is not allowed but cloning a whole graph containing one is
|
||||
* ok.
|
||||
*/
|
||||
@Test
|
||||
public void testClone() {
|
||||
StructuredGraph g = parseEager("preventPeelSnippet", AllowAssumptions.NO);
|
||||
g.copy(g.getDebug());
|
||||
}
|
||||
|
||||
private static List<NodeCount> getNodeCountAnnotations(StructuredGraph graph) {
|
||||
ResolvedJavaMethod method = graph.method();
|
||||
AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class);
|
||||
if (snippet != null) {
|
||||
return Arrays.asList(snippet.value());
|
||||
}
|
||||
|
||||
NodeCount single = method.getAnnotation(NodeCount.class);
|
||||
if (single != null) {
|
||||
return Collections.singletonList(single);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
|
||||
for (int i = 0; i < anchors.size(); i++) {
|
||||
ControlFlowAnchorNode a = anchors.get(i);
|
||||
for (int j = i + 1; j < anchors.size(); j++) {
|
||||
ControlFlowAnchorNode b = anchors.get(j);
|
||||
if (a.valueEquals(b)) {
|
||||
Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (NodeCount nodeCount : getNodeCountAnnotations(graph)) {
|
||||
NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass());
|
||||
Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
|
||||
public class DeoptimizeDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
public static boolean inCompiledCode() {
|
||||
return GraalDirectives.inCompiledCode();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInCompiledCode() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("inCompiledCode");
|
||||
|
||||
Result interpreted = executeExpected(method, null);
|
||||
assertEquals(new Result(false, null), interpreted);
|
||||
|
||||
Result compiled = executeActual(method, null);
|
||||
assertEquals(new Result(true, null), compiled);
|
||||
}
|
||||
|
||||
public static boolean deoptimizeSnippet() {
|
||||
GraalDirectives.deoptimize();
|
||||
return GraalDirectives.inCompiledCode(); // should always return false
|
||||
}
|
||||
|
||||
public static boolean deoptimizeAndInvalidateSnippet() {
|
||||
GraalDirectives.deoptimizeAndInvalidate();
|
||||
return GraalDirectives.inCompiledCode(); // should always return false
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeoptimize() {
|
||||
test("deoptimizeSnippet");
|
||||
}
|
||||
|
||||
private boolean testDeoptimizeCheckValid(ResolvedJavaMethod method) {
|
||||
Result expected = executeExpected(method, null);
|
||||
|
||||
InstalledCode code = getCode(method);
|
||||
Result actual;
|
||||
try {
|
||||
actual = new Result(code.executeVarargs(), null);
|
||||
} catch (Exception e) {
|
||||
actual = new Result(null, e);
|
||||
}
|
||||
|
||||
assertEquals(expected, actual);
|
||||
return code.isValid();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeoptimizeAndInvalidate() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeAndInvalidateSnippet");
|
||||
boolean valid = testDeoptimizeCheckValid(method);
|
||||
Assert.assertFalse("code should be invalidated", valid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeoptimizeDontInvalidate() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("deoptimizeSnippet");
|
||||
boolean valid = testDeoptimizeCheckValid(method);
|
||||
Assert.assertTrue("code should still be valid", valid);
|
||||
}
|
||||
|
||||
public static int zeroBranchProbabilitySnippet(boolean flag) {
|
||||
if (GraalDirectives.injectBranchProbability(0, flag)) {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 1;
|
||||
} else {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroBranchProbability() {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("zeroBranchProbabilitySnippet");
|
||||
Result expected = executeExpected(method, null, true);
|
||||
|
||||
InstalledCode code = getCode(method);
|
||||
Result actual;
|
||||
try {
|
||||
actual = new Result(code.executeVarargs(true), null);
|
||||
} catch (Exception e) {
|
||||
actual = new Result(null, e);
|
||||
}
|
||||
|
||||
assertEquals(expected, actual);
|
||||
assertFalse("code should be invalidated", code.isValid());
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
import org.graalvm.compiler.nodes.LoopBeginNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
|
||||
public class IterationDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
public static int loopFrequencySnippet(int arg) {
|
||||
int x = arg;
|
||||
while (GraalDirectives.injectIterationCount(128, x > 1)) {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent loop peeling or unrolling
|
||||
if (x % 2 == 0) {
|
||||
x /= 2;
|
||||
} else {
|
||||
x = 3 * x + 1;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopFrequency() {
|
||||
test("loopFrequencySnippet", 7);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.TYPE);
|
||||
Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count());
|
||||
|
||||
LoopBeginNode loopBeginNode = loopBeginNodes.first();
|
||||
Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0);
|
||||
}
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.ReturnNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.calc.AddNode;
|
||||
import org.graalvm.compiler.nodes.calc.ConditionalNode;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraalDirectives#opaque}.
|
||||
*
|
||||
* There are two snippets for each kind:
|
||||
* <ul>
|
||||
* <li>opaque<Kind>Snippet verifies that constant folding is prevented by the opaque
|
||||
* directive.
|
||||
* <li><kind>Snippet verifies that constant folding does happen if the opaque directive is not
|
||||
* there.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
public class OpaqueDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
private @interface OpaqueSnippet {
|
||||
Class<?> expectedReturnNode();
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConstantNode.class)
|
||||
public static boolean booleanSnippet() {
|
||||
return 5 > 3;
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
|
||||
public static boolean opaqueBooleanSnippet() {
|
||||
return 5 > GraalDirectives.opaque(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoolean() {
|
||||
test("booleanSnippet");
|
||||
test("opaqueBooleanSnippet");
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConstantNode.class)
|
||||
public static int intSnippet() {
|
||||
return 5 + 3;
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = AddNode.class)
|
||||
public static int opaqueIntSnippet() {
|
||||
return 5 + GraalDirectives.opaque(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt() {
|
||||
test("intSnippet");
|
||||
test("opaqueIntSnippet");
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConstantNode.class)
|
||||
public static double doubleSnippet() {
|
||||
return 5. + 3.;
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = AddNode.class)
|
||||
public static double opaqueDoubleSnippet() {
|
||||
return 5. + GraalDirectives.opaque(3.);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDouble() {
|
||||
test("doubleSnippet");
|
||||
test("opaqueDoubleSnippet");
|
||||
}
|
||||
|
||||
private static class Dummy {
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConstantNode.class)
|
||||
public static boolean objectSnippet() {
|
||||
Object obj = new Dummy();
|
||||
return obj == null;
|
||||
}
|
||||
|
||||
@OpaqueSnippet(expectedReturnNode = ConditionalNode.class)
|
||||
public static boolean opaqueObjectSnippet() {
|
||||
Object obj = new Dummy();
|
||||
return GraalDirectives.opaque(obj) == null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObject() {
|
||||
test("objectSnippet");
|
||||
test("opaqueObjectSnippet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
|
||||
for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
|
||||
Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives.test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
import org.graalvm.compiler.nodes.AbstractBeginNode;
|
||||
import org.graalvm.compiler.nodes.IfNode;
|
||||
import org.graalvm.compiler.nodes.ReturnNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ProbabilityDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
/**
|
||||
* Called before a test is compiled.
|
||||
*/
|
||||
@Override
|
||||
protected void before(ResolvedJavaMethod method) {
|
||||
// don't let -Xcomp pollute profile
|
||||
method.reprofile();
|
||||
}
|
||||
|
||||
public static int branchProbabilitySnippet(int arg) {
|
||||
if (GraalDirectives.injectBranchProbability(0.125, arg > 0)) {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 1;
|
||||
} else {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBranchProbability() {
|
||||
test("branchProbabilitySnippet", 5);
|
||||
}
|
||||
|
||||
public static int branchProbabilitySnippet2(int arg) {
|
||||
if (!GraalDirectives.injectBranchProbability(0.125, arg <= 0)) {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 2;
|
||||
} else {
|
||||
GraalDirectives.controlFlowAnchor(); // prevent removal of the if
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBranchProbability2() {
|
||||
test("branchProbabilitySnippet2", 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLowTierGraph(StructuredGraph graph) {
|
||||
NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
|
||||
Assert.assertEquals("IfNode count", 1, ifNodes.count());
|
||||
|
||||
IfNode ifNode = ifNodes.first();
|
||||
AbstractBeginNode oneSuccessor;
|
||||
if (returnValue(ifNode.trueSuccessor()) == 1) {
|
||||
oneSuccessor = ifNode.trueSuccessor();
|
||||
} else {
|
||||
assert returnValue(ifNode.falseSuccessor()) == 1;
|
||||
oneSuccessor = ifNode.falseSuccessor();
|
||||
}
|
||||
Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(oneSuccessor), 0);
|
||||
}
|
||||
|
||||
private static int returnValue(AbstractBeginNode b) {
|
||||
ControlFlowAnchorNode anchor = (ControlFlowAnchorNode) b.next();
|
||||
ReturnNode returnNode = (ReturnNode) anchor.next();
|
||||
return returnNode.result().asJavaConstant().asInt();
|
||||
}
|
||||
}
|
||||
@ -1,401 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.directives;
|
||||
|
||||
// JaCoCo Exclude
|
||||
|
||||
/**
|
||||
* Directives that influence the compilation of methods by Graal. They don't influence the semantics
|
||||
* of the code, but they are useful for unit testing and benchmarking.
|
||||
*/
|
||||
public final class GraalDirectives {
|
||||
|
||||
public static final double LIKELY_PROBABILITY = 0.75;
|
||||
public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY;
|
||||
|
||||
public static final double SLOWPATH_PROBABILITY = 0.0001;
|
||||
public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY;
|
||||
|
||||
/**
|
||||
* Directive for the compiler to fall back to the bytecode interpreter at this point.
|
||||
*/
|
||||
public static void deoptimize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate
|
||||
* the compiled code and reprofile the method.
|
||||
*/
|
||||
public static void deoptimizeAndInvalidate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate
|
||||
* the compiled code, record a speculation and reprofile the method.
|
||||
*/
|
||||
public static void deoptimizeAndInvalidateWithSpeculation() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value indicating whether the method is executed in Graal-compiled code.
|
||||
*/
|
||||
public static boolean inCompiledCode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method will never be duplicated by control flow optimizations in the compiler.
|
||||
*/
|
||||
public static void controlFlowAnchor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method will assume a stable dimension array if {@code t} is a constant array
|
||||
* and {@code i} a constant integer.
|
||||
*/
|
||||
public static <T> T assumeStableDimension(T t, @SuppressWarnings("unused") int i) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method will force the compiler to assume this instruction has a visible memory
|
||||
* effect killing all memory locations.
|
||||
*/
|
||||
public static void sideEffect() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method will force the compiler to assume this instruction has a visible memory
|
||||
* effect killing all memory locations.
|
||||
*/
|
||||
public static int sideEffect(@SuppressWarnings("unused") int a) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a probability for the given condition into the profiling information of a branch
|
||||
* instruction. The probability must be a value between 0.0 and 1.0 (inclusive).
|
||||
*
|
||||
* Example usage (it specifies that the likelihood for a to be greater than b is 90%):
|
||||
*
|
||||
* <code>
|
||||
* if (injectBranchProbability(0.9, a > b)) {
|
||||
* // ...
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* There are predefined constants for commonly used probabilities (see
|
||||
* {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY},
|
||||
* {@link #FASTPATH_PROBABILITY} ).
|
||||
*
|
||||
* @param probability the probability value between 0.0 and 1.0 that should be injected
|
||||
*/
|
||||
public static boolean injectBranchProbability(double probability, boolean condition) {
|
||||
assert probability >= 0.0 && probability <= 1.0;
|
||||
return condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects an average iteration count of a loop into the probability information of a loop exit
|
||||
* condition. The iteration count specifies how often the condition is checked, i.e. in for and
|
||||
* while loops it is one more than the body iteration count, and in do-while loops it is equal
|
||||
* to the body iteration count. The iteration count must be >= 1.0.
|
||||
*
|
||||
* Example usage (it specifies that the expected iteration count of the loop condition is 500,
|
||||
* so the iteration count of the loop body is 499):
|
||||
*
|
||||
* <code>
|
||||
* for (int i = 0; injectIterationCount(500, i < array.length); i++) {
|
||||
* // ...
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param iterations the expected number of iterations that should be injected
|
||||
*/
|
||||
public static boolean injectIterationCount(double iterations, boolean condition) {
|
||||
return injectBranchProbability(1. - 1. / iterations, condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(boolean value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(byte value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(short value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(char value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(int value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(long value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(float value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(double value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a value, making sure the compiler doesn't optimize away the computation of this
|
||||
* value, even if it is otherwise unused.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void blackhole(Object value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(boolean value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(byte value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(short value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(char value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(int value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(long value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(float value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(double value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a value to be kept in a register.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void bindToRegister(Object value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Spills all caller saved registers.
|
||||
*/
|
||||
public static void spillRegisters() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static boolean opaque(boolean value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static byte opaque(byte value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static short opaque(short value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static char opaque(char value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static int opaque(int value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static long opaque(long value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static float opaque(float value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static double opaque(double value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing, but also make sure the compiler doesn't do any optimizations across this call.
|
||||
*
|
||||
* For example, the compiler will constant fold the expression 5 * 3, but the expression 5 *
|
||||
* opaque(3) will result in a real multiplication, because the compiler will not see that
|
||||
* opaque(3) is a constant.
|
||||
*/
|
||||
public static <T> T opaque(T value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static <T> T guardingNonNull(T value) {
|
||||
if (value == null) {
|
||||
deoptimize();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given object will be virtual (escape analyzed) at all points that are
|
||||
* dominated by the current position.
|
||||
*/
|
||||
public static void ensureVirtualized(@SuppressWarnings("unused") Object object) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given object will be virtual at the current position.
|
||||
*/
|
||||
public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
|
||||
}
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a class that substitutes methods of another specified class. The substitute methods are
|
||||
* exactly those annotated by {@link MethodSubstitution}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ClassSubstitution {
|
||||
|
||||
/**
|
||||
* Specifies the original class.
|
||||
* <p>
|
||||
* If the default value is specified for this element, then a non-default value must be given
|
||||
* for the {@link #className()} element.
|
||||
*/
|
||||
Class<?> value() default ClassSubstitution.class;
|
||||
|
||||
/**
|
||||
* Specifies the original class or classes if a single class is being used for multiple
|
||||
* substitutions.
|
||||
* <p>
|
||||
* This method is provided for cases where the original class is not accessible (according to
|
||||
* Java language access control rules).
|
||||
* <p>
|
||||
* If the default value is specified for this element, then a non-default value must be given
|
||||
* for the {@link #value()} element.
|
||||
*/
|
||||
String[] className() default {};
|
||||
|
||||
/**
|
||||
* Determines if the substitutions are for classes that may not be part of the runtime.
|
||||
* Substitutions for such classes are omitted if the original classes cannot be found. If
|
||||
* multiple classes are specified using {@link #className()} and {@link #optional()} is false,
|
||||
* then at least one of the classes is required to be reachable.
|
||||
*/
|
||||
boolean optional() default false;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated method
|
||||
* is replaced with a constant obtained by calling the annotated method via reflection.
|
||||
*
|
||||
* All arguments to such a method (including the receiver if applicable) must be compile-time
|
||||
* constants.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Fold {
|
||||
|
||||
/**
|
||||
* Annotates a parameter to an {@link Fold}-annotated method. This parameter will be
|
||||
* automatically injected by the compiler. A call from non-generated code must always pass
|
||||
* {@code null} for an injected parameter.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface InjectedParameter {
|
||||
}
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import jdk.vm.ci.meta.Signature;
|
||||
|
||||
/**
|
||||
* Denotes a method whose body is used by a compiler as the substitute (or intrinsification) of
|
||||
* another method. The exact mechanism used to do the substitution is compiler dependent but every
|
||||
* compiler should require substitute methods to be annotated with {@link MethodSubstitution}.
|
||||
*
|
||||
* A compiler may support partial intrinsification where only a part of a method is implemented by
|
||||
* the compiler. The unsupported path is expressed by a call to either the original or substitute
|
||||
* method from within the substitute method. Such as call is a <i>partial intrinsic exit</i>.
|
||||
*
|
||||
* For example, here's a HotSpot specific intrinsic for {@link Array#newInstance(Class, int)} that
|
||||
* only handles the case where the VM representation of the array class to be instantiated already
|
||||
* exists:
|
||||
*
|
||||
* <pre>
|
||||
* @MethodSubstitution
|
||||
* public static Object newInstance(Class<?> componentType, int length) {
|
||||
* if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
|
||||
* // Array class not yet created - exit the intrinsic and call the original method
|
||||
* return newInstance(componentType, length);
|
||||
* }
|
||||
* return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Here's the same intrinsification where the exit is expressed as a call to the original method:
|
||||
*
|
||||
* <pre>
|
||||
* @MethodSubstitution
|
||||
* public static Object newInstance(Class<?> componentType, int length) {
|
||||
* if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
|
||||
* // Array class not yet created - exit the intrinsic and call the original method
|
||||
* return java.lang.reflect.newInstance(componentType, length);
|
||||
* }
|
||||
* return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* A condition for a partial intrinsic exit is that it is uses the unmodified parameters of the
|
||||
* substitute as arguments to the partial intrinsic exit call. There must also be no side effecting
|
||||
* instruction between the start of the substitute method and the partial intrinsic exit.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface MethodSubstitution {
|
||||
|
||||
/**
|
||||
* Gets the name of the original method.
|
||||
* <p>
|
||||
* If the default value is specified for this element, then the name of the original method is
|
||||
* same as the substitute method.
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* Determines if the original method is static.
|
||||
*/
|
||||
boolean isStatic() default true;
|
||||
|
||||
/**
|
||||
* Gets the {@linkplain Signature#toMethodDescriptor signature} of the original method.
|
||||
* <p>
|
||||
* If the default value is specified for this element, then the signature of the original method
|
||||
* is the same as the substitute method.
|
||||
*/
|
||||
String signature() default "";
|
||||
|
||||
/**
|
||||
* Determines if the substitution is for a method that may not be part of the runtime. For
|
||||
* example, a method introduced in a later JDK version. Substitutions for such methods are
|
||||
* omitted if the original method cannot be found.
|
||||
*/
|
||||
boolean optional() default false;
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering
|
||||
* nodes that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode).
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Snippet {
|
||||
|
||||
/**
|
||||
* A partial intrinsic exits by (effectively) calling the intrinsified method. Normally, this
|
||||
* call must use exactly the same arguments as the call that is being intrinsified. For well
|
||||
* known snippets that are used after frame state assignment, we want to relax this restriction.
|
||||
*/
|
||||
boolean allowPartialIntrinsicArgumentMismatch() default false;
|
||||
|
||||
/**
|
||||
* Denotes a snippet parameter representing 0 or more arguments that will be bound during
|
||||
* snippet template instantiation. During snippet template creation, its value must be an array
|
||||
* whose length specifies the number of arguments (the contents of the array are ignored) bound
|
||||
* to the parameter during instantiation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface VarargsParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes a snippet parameter that will bound to a constant value during snippet template
|
||||
* instantiation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ConstantParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes a snippet parameter that will bound to a non-null value during snippet template
|
||||
* instantiation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface NonNullParameter {
|
||||
}
|
||||
}
|
||||
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
|
||||
/**
|
||||
* Reflection operations on values represented as {@linkplain JavaConstant constants} for the
|
||||
* processing of snippets. Snippets need a direct access to the value of object constants, which is
|
||||
* not allowed in other parts of Graal to enforce compiler-VM separation.
|
||||
* <p>
|
||||
* This interface must not be used in Graal code that is not related to snippet processing.
|
||||
*/
|
||||
public interface SnippetReflectionProvider {
|
||||
|
||||
/**
|
||||
* Creates a boxed {@link JavaKind#Object object} constant.
|
||||
*
|
||||
* @param object the object value to box
|
||||
* @return a constant containing {@code object}
|
||||
*/
|
||||
JavaConstant forObject(Object object);
|
||||
|
||||
/**
|
||||
* Gets the object reference a given constant represents if it is of a given type. The constant
|
||||
* must have kind {@link JavaKind#Object}.
|
||||
*
|
||||
* @param type the expected type of the object represented by {@code constant}. If the object is
|
||||
* required to be of this type, then wrap the call to this method in
|
||||
* {@link Objects#requireNonNull(Object)}.
|
||||
* @param constant an object constant
|
||||
* @return the object value represented by {@code constant} cast to {@code type} if it is an
|
||||
* {@link Class#isInstance(Object) instance of} {@code type} otherwise {@code null}
|
||||
*/
|
||||
<T> T asObject(Class<T> type, JavaConstant constant);
|
||||
|
||||
/**
|
||||
* Creates a boxed constant for the given kind from an Object. The object needs to be of the
|
||||
* Java boxed type corresponding to the kind.
|
||||
*
|
||||
* @param kind the kind of the constant to create
|
||||
* @param value the Java boxed value: a {@link Byte} instance for {@link JavaKind#Byte}, etc.
|
||||
* @return the boxed copy of {@code value}
|
||||
*/
|
||||
default JavaConstant forBoxed(JavaKind kind, Object value) {
|
||||
if (kind == JavaKind.Object) {
|
||||
return forObject(value);
|
||||
} else {
|
||||
return JavaConstant.forBoxedPrimitive(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value to bind to an injected parameter in a node intrinsic.
|
||||
*
|
||||
* @param type the type of a parameter in a node intrinsic constructor
|
||||
* @return the value that should be bound to the parameter when invoking the constructor or null
|
||||
* if this provider cannot provide a value of the requested type
|
||||
*/
|
||||
<T> T getInjectedNodeIntrinsicParameter(Class<T> type);
|
||||
|
||||
/**
|
||||
* Get the original Java class corresponding to a {@link ResolvedJavaType}.
|
||||
*
|
||||
* @param type the type for which the original Java class is requested
|
||||
* @return the original Java class corresponding to {@code type} or {@code null} if this object
|
||||
* cannot map {@link ResolvedJavaType} instances to {@link Class} instances
|
||||
*/
|
||||
Class<?> originalClass(ResolvedJavaType type);
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.replacements;
|
||||
|
||||
/**
|
||||
* Marker interface for classes that cache snippet templates.
|
||||
*/
|
||||
public interface SnippetTemplateCache {
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.runtime;
|
||||
|
||||
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||
|
||||
/**
|
||||
* Graal specific extension of the {@link JVMCICompiler} interface.
|
||||
*/
|
||||
public interface GraalJVMCICompiler extends JVMCICompiler {
|
||||
|
||||
GraalRuntime getGraalRuntime();
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.runtime;
|
||||
|
||||
import jdk.vm.ci.common.JVMCIError;
|
||||
|
||||
public interface GraalRuntime {
|
||||
|
||||
String getName();
|
||||
|
||||
<T> T getCapability(Class<T> clazz);
|
||||
|
||||
default <T> T getRequiredCapability(Class<T> clazz) {
|
||||
T ret = getCapability(clazz);
|
||||
if (ret == null) {
|
||||
throw new JVMCIError("The VM does not expose the required Graal capability %s.", clazz.getName());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.test;
|
||||
|
||||
/**
|
||||
* A class loader that exports all packages in the module defining the class loader to all classes
|
||||
* in the unnamed module associated with the loader.
|
||||
*/
|
||||
public class ExportingClassLoader extends ClassLoader {
|
||||
public ExportingClassLoader() {
|
||||
ModuleSupport.exportAllPackagesTo(getClass(), this);
|
||||
}
|
||||
|
||||
public ExportingClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
ModuleSupport.exportAllPackagesTo(getClass(), this);
|
||||
}
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.test;
|
||||
|
||||
import java.util.Formatter;
|
||||
|
||||
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
|
||||
import org.graalvm.compiler.api.runtime.GraalRuntime;
|
||||
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||
import jdk.vm.ci.services.Services;
|
||||
|
||||
/**
|
||||
* Access point for {@linkplain #getRuntime() retrieving} the {@link GraalRuntime} instance of the
|
||||
* system compiler from unit tests.
|
||||
*/
|
||||
public class Graal {
|
||||
|
||||
private static final GraalRuntime runtime = initializeRuntime();
|
||||
|
||||
private static GraalRuntime initializeRuntime() {
|
||||
Services.initializeJVMCI();
|
||||
JVMCICompiler compiler = JVMCI.getRuntime().getCompiler();
|
||||
if (compiler instanceof GraalJVMCICompiler) {
|
||||
GraalJVMCICompiler graal = (GraalJVMCICompiler) compiler;
|
||||
return graal.getGraalRuntime();
|
||||
} else {
|
||||
return new InvalidGraalRuntime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton {@link GraalRuntime} instance available to unit tests.
|
||||
*/
|
||||
public static GraalRuntime getRuntime() {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a capability provided by the {@link GraalRuntime} instance available to the application.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the capability is not available
|
||||
*/
|
||||
public static <T> T getRequiredCapability(Class<T> clazz) {
|
||||
T t = getRuntime().getCapability(clazz);
|
||||
if (t == null) {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
String vmName = System.getProperty("java.vm.name");
|
||||
Formatter errorMessage = new Formatter();
|
||||
if (getRuntime().getClass() == InvalidGraalRuntime.class) {
|
||||
errorMessage.format("The VM does not support the Graal API.%n");
|
||||
} else {
|
||||
errorMessage.format("The VM does not expose required Graal capability %s.%n", clazz.getName());
|
||||
}
|
||||
errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
|
||||
errorMessage.format("Currently used VM configuration is: %s", vmName);
|
||||
throw new UnsupportedOperationException(errorMessage.toString());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
private static final class InvalidGraalRuntime implements GraalRuntime {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getCapability(Class<T> clazz) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class GraalAPITest {
|
||||
|
||||
@Test
|
||||
public void testRuntimeAvailable() {
|
||||
assertNotNull(Graal.getRuntime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeNamed() {
|
||||
assertNotNull(Graal.getRuntime().getName());
|
||||
}
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.api.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.graalvm.compiler.debug.DebugOptions;
|
||||
|
||||
import jdk.internal.module.Modules;
|
||||
|
||||
public class ModuleSupport {
|
||||
|
||||
public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
|
||||
Module moduleToExport = moduleMember.getModule();
|
||||
Module requestorModule = requestor.getModule();
|
||||
if (moduleToExport != requestorModule) {
|
||||
Modules.addExports(moduleToExport, packageName, requestorModule);
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportAllPackagesTo(Class<?> moduleMember, Class<?> requestor) {
|
||||
Module moduleToExport = moduleMember.getModule();
|
||||
Module requestorModule = requestor.getModule();
|
||||
if (moduleToExport != requestorModule) {
|
||||
for (String packageName : moduleToExport.getPackages()) {
|
||||
Modules.addExports(moduleToExport, packageName, requestorModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportAllPackagesTo(Class<?> moduleMember, ClassLoader cl) {
|
||||
Module moduleToExport = moduleMember.getModule();
|
||||
Module unnamedModule = cl.getUnnamedModule();
|
||||
for (String packageName : moduleToExport.getPackages()) {
|
||||
Modules.addExports(moduleToExport, packageName, unnamedModule);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void exportAndOpenAllPackagesToUnnamed(String name) {
|
||||
Module module = ModuleLayer.boot().findModule(name).orElseThrow();
|
||||
Set<String> packages = module.getPackages();
|
||||
for (String pkg : packages) {
|
||||
Modules.addExportsToAllUnnamed(module, pkg);
|
||||
Modules.addOpensToAllUnnamed(module, pkg);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getJRTGraalClassNames() throws IOException {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
|
||||
Module graalModule = DebugOptions.class.getModule();
|
||||
Set<String> graalModuleSet = new HashSet<>();
|
||||
graalModuleSet.add(graalModule.getName());
|
||||
for (Module module : graalModule.getLayer().modules()) {
|
||||
if (requires(module, graalModule)) {
|
||||
graalModuleSet.add(module.getName());
|
||||
}
|
||||
}
|
||||
|
||||
Path top = fs.getPath("/modules/");
|
||||
Files.find(top, Integer.MAX_VALUE,
|
||||
(path, attrs) -> attrs.isRegularFile()).forEach(p -> {
|
||||
int nameCount = p.getNameCount();
|
||||
if (nameCount > 2) {
|
||||
String base = p.getName(nameCount - 1).toString();
|
||||
if (base.endsWith(".class") && !base.equals("module-info.class")) {
|
||||
String module = p.getName(1).toString();
|
||||
if (graalModuleSet.contains(module)) {
|
||||
// Strip module prefix and convert to dotted
|
||||
// form
|
||||
String className = p.subpath(2, nameCount).toString().replace('/', '.');
|
||||
// Strip ".class" suffix
|
||||
className = className.replace('/', '.').substring(0, className.length() - ".class".length());
|
||||
classNames.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return classNames;
|
||||
}
|
||||
|
||||
private static boolean requires(Module module, Module graalModule) {
|
||||
ModuleLayer graalLayer = graalModule.getLayer();
|
||||
for (Requires r : module.getDescriptor().requires()) {
|
||||
if (r.name().equals(graalModule.getName())) {
|
||||
return true;
|
||||
}
|
||||
Module dep = graalLayer.findModule(r.name()).get();
|
||||
if (requires(dep, graalModule)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,286 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.aarch64.AArch64.CPUFeature;
|
||||
import jdk.vm.ci.code.Architecture;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
public class AArch64AddressingModeTest extends GraalTest {
|
||||
|
||||
private AArch64MacroAssembler masm;
|
||||
private TestProtectedAssembler asm;
|
||||
private Register base;
|
||||
private Register index;
|
||||
private Register scratch;
|
||||
|
||||
private static EnumSet<AArch64.CPUFeature> computeFeatures() {
|
||||
EnumSet<AArch64.CPUFeature> features = EnumSet.noneOf(AArch64.CPUFeature.class);
|
||||
features.add(CPUFeature.FP);
|
||||
return features;
|
||||
}
|
||||
|
||||
private static EnumSet<AArch64.Flag> computeFlags() {
|
||||
EnumSet<AArch64.Flag> flags = EnumSet.noneOf(AArch64.Flag.class);
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static TargetDescription createTarget() {
|
||||
final int stackFrameAlignment = 16;
|
||||
final int implicitNullCheckLimit = 4096;
|
||||
final boolean inlineObjects = true;
|
||||
Architecture arch = new AArch64(computeFeatures(), computeFlags());
|
||||
return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupEnvironment() {
|
||||
TargetDescription target = createTarget();
|
||||
masm = new AArch64MacroAssembler(target);
|
||||
asm = new TestProtectedAssembler(target);
|
||||
base = AArch64.r10;
|
||||
index = AArch64.r13;
|
||||
scratch = AArch64.r15;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateAddressPlan() {
|
||||
AddressGenerationPlan plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 0);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
|
||||
(plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 1);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
|
||||
(plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(8) - 1, false, 0);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 1);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 2, false, 4);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(0, false, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(0, false, 0);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(9), false, 0);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13), false, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(12), false, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(-(NumUtil.getNbitNumberInt(12) << 12), false, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), true, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 3, true, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
|
||||
plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13) << 3, true, 8);
|
||||
Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressNoAction() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12) << 3, AArch64.zr, false, 8, null, false);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.IMMEDIATE_SCALED && address.getBase().equals(base) &&
|
||||
address.getOffset().equals(AArch64.zr) && address.getImmediateRaw() == NumUtil.getNbitNumberInt(12));
|
||||
// No code generated.
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddIndex() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, null, true);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
|
||||
asm.add(64, index, index, NumUtil.getNbitNumberInt(8) << 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddIndexNoOverwrite() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, scratch, false);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(scratch));
|
||||
asm.add(64, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddBaseNoOverwrite() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, scratch, false);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(scratch) && address.getOffset().equals(index));
|
||||
asm.add(64, scratch, base, NumUtil.getNbitNumberInt(12));
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddBase() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, null, true);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
|
||||
asm.add(64, base, base, NumUtil.getNbitNumberInt(12));
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddIndexNoOverwriteExtend() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, false);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
|
||||
address.getOffset().equals(scratch) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
|
||||
asm.add(32, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeAddressAddIndexExtend() {
|
||||
AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, true);
|
||||
Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
|
||||
address.getOffset().equals(index) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
|
||||
asm.add(32, index, index, NumUtil.getNbitNumberInt(8) << 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressUnscaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, NumUtil.getNbitNumberInt(8));
|
||||
masm.loadAddress(dst, address, 8);
|
||||
asm.add(64, dst, base, NumUtil.getNbitNumberInt(8));
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressUnscaled2() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, -NumUtil.getNbitNumberInt(8));
|
||||
masm.loadAddress(dst, address, 8);
|
||||
asm.sub(64, dst, base, NumUtil.getNbitNumberInt(8));
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressScaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(12));
|
||||
masm.loadAddress(dst, address, 8);
|
||||
asm.add(64, dst, base, NumUtil.getNbitNumberInt(9) << 3);
|
||||
asm.add(64, dst, dst, NumUtil.getNbitNumberInt(3) << 12);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressScaledLowerOnly() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(5));
|
||||
masm.loadAddress(dst, address, 8);
|
||||
asm.add(64, dst, base, NumUtil.getNbitNumberInt(5) << 3);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressScaledHigherOnly() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, 1 << 11);
|
||||
masm.loadAddress(dst, address, 8);
|
||||
asm.add(64, dst, base, 1 << 11 << 3);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressRegisterOffsetUnscaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, false);
|
||||
masm.loadAddress(dst, address, 4);
|
||||
asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressRegisterOffsetScaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, true);
|
||||
masm.loadAddress(dst, address, 4);
|
||||
asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressExtendedRegisterOffsetUnscaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, false, AArch64Assembler.ExtendType.SXTW);
|
||||
masm.loadAddress(dst, address, 4);
|
||||
asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadAddressExtendedRegisterOffsetScaled() {
|
||||
Register dst = AArch64.r26;
|
||||
AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, true, AArch64Assembler.ExtendType.SXTW);
|
||||
masm.loadAddress(dst, address, 4);
|
||||
asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 2);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares assembly generated by the macro assembler to the hand-generated assembly.
|
||||
*/
|
||||
private void compareAssembly() {
|
||||
byte[] expected = asm.close(true);
|
||||
byte[] actual = masm.close(true);
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited. 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.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.asm.test.AssemblerTest;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.aarch64.AArch64Kind;
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterArray;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
public class AArch64BitCountAssemblerTest extends AssemblerTest {
|
||||
@Before
|
||||
public void checkAArch64() {
|
||||
assumeTrue("skipping non AArch64 specific test", codeCache.getTarget().arch instanceof AArch64);
|
||||
}
|
||||
|
||||
public interface AArch64CodeGenTestCase {
|
||||
CodeGenTest create();
|
||||
|
||||
int getExpected();
|
||||
}
|
||||
|
||||
private class AArch64BitCountCodeGenTestCase<T extends Number> implements AArch64CodeGenTestCase {
|
||||
final T value;
|
||||
final int size;
|
||||
|
||||
AArch64BitCountCodeGenTestCase(T x, int size) {
|
||||
assert x instanceof Integer || x instanceof Long;
|
||||
this.value = x;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeGenTest create() {
|
||||
return (CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) -> {
|
||||
AArch64MacroAssembler masm = new AArch64MacroAssembler(target);
|
||||
Register dst = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
Register src = asRegister(cc.getArgument(0));
|
||||
// Generate a nop first as AArch64 Hotspot requires instruction at nmethod verified
|
||||
// entry to be a jump or nop. (See https://github.com/oracle/graal/issues/1439)
|
||||
masm.nop();
|
||||
RegisterArray registers = registerConfig.filterAllocatableRegisters(AArch64Kind.V64_BYTE, registerConfig.getAllocatableRegisters());
|
||||
masm.popcnt(size, dst, src, registers.get(registers.size() - 1));
|
||||
masm.ret(AArch64.lr);
|
||||
return masm.close(true);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExpected() {
|
||||
if (value instanceof Integer) {
|
||||
return Integer.bitCount((Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
return Long.bitCount((Long) value);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testBitCount() {
|
||||
AArch64CodeGenTestCase[] tests = {
|
||||
new AArch64BitCountCodeGenTestCase<>(0, JavaKind.Int.getByteCount() * Byte.SIZE),
|
||||
new AArch64BitCountCodeGenTestCase<>(1522767384, JavaKind.Int.getByteCount() * Byte.SIZE),
|
||||
new AArch64BitCountCodeGenTestCase<>(0L, JavaKind.Long.getByteCount() * Byte.SIZE),
|
||||
new AArch64BitCountCodeGenTestCase<>(81985529216486895L, JavaKind.Long.getByteCount() * Byte.SIZE),
|
||||
};
|
||||
|
||||
assertReturn("intStub", tests[0].create(), tests[0].getExpected(), ((AArch64BitCountCodeGenTestCase<Integer>) tests[0]).getValue());
|
||||
assertReturn("intStub", tests[1].create(), tests[1].getExpected(), ((AArch64BitCountCodeGenTestCase<Integer>) tests[1]).getValue());
|
||||
assertReturn("longStub", tests[2].create(), tests[2].getExpected(), ((AArch64BitCountCodeGenTestCase<Long>) tests[2]).getValue());
|
||||
assertReturn("longStub", tests[3].create(), tests[3].getExpected(), ((AArch64BitCountCodeGenTestCase<Long>) tests[3]).getValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int intStub(int x) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int longStub(long x) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited. 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.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
|
||||
public class AArch64InstructionEncodingTest extends GraalTest {
|
||||
@Before
|
||||
public void checkAArch64() {
|
||||
assumeTrue("skipping non AArch64 specific test", JVMCI.getRuntime().getHostJVMCIBackend().getTarget().arch instanceof AArch64);
|
||||
}
|
||||
|
||||
private abstract class AArch64InstructionEncodingTestCase {
|
||||
private byte[] actual;
|
||||
private byte[] expected;
|
||||
TestProtectedAssembler assembler;
|
||||
|
||||
AArch64InstructionEncodingTestCase(int expected) {
|
||||
this.expected = ByteBuffer.allocate(Integer.BYTES).putInt(expected).array();
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
assembler = new TestProtectedAssembler(target);
|
||||
}
|
||||
|
||||
int getExpected() {
|
||||
return ByteBuffer.wrap(expected).getInt();
|
||||
}
|
||||
|
||||
int getActual() {
|
||||
return ByteBuffer.wrap(actual).getInt();
|
||||
}
|
||||
|
||||
void closeAssembler() {
|
||||
this.actual = assembler.close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private class CntEncodingTestCase extends AArch64InstructionEncodingTestCase {
|
||||
CntEncodingTestCase(int expected, int size, Register dst, Register src) {
|
||||
super(expected);
|
||||
assembler.cnt(size, dst, src);
|
||||
closeAssembler();
|
||||
}
|
||||
}
|
||||
|
||||
private class AddvEncodingTestCase extends AArch64InstructionEncodingTestCase {
|
||||
AddvEncodingTestCase(int expected, int size, AArch64Assembler.SIMDElementSize laneWidth, Register dst, Register src) {
|
||||
super(expected);
|
||||
assembler.addv(size, laneWidth, dst, src);
|
||||
closeAssembler();
|
||||
}
|
||||
}
|
||||
|
||||
private class UmovEncodingTestCase extends AArch64InstructionEncodingTestCase {
|
||||
UmovEncodingTestCase(int expected, int size, Register dst, int srcIdx, Register src) {
|
||||
super(expected);
|
||||
assembler.umov(size, dst, srcIdx, src);
|
||||
closeAssembler();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int invalidInstructionCode = 0x00000000;
|
||||
|
||||
private void assertWrapper(AArch64InstructionEncodingTestCase testCase) {
|
||||
assertDeepEquals(testCase.getActual(), testCase.getExpected());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCnt() {
|
||||
assertWrapper(new CntEncodingTestCase(0x0058200e, 64, AArch64.v0, AArch64.v0));
|
||||
assertWrapper(new CntEncodingTestCase(0x3f58204e, 128, AArch64.v31, AArch64.v1));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testCntWithInvalidDataSize() {
|
||||
new CntEncodingTestCase(invalidInstructionCode, 32, AArch64.v5, AArch64.v5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddv() {
|
||||
assertWrapper(new AddvEncodingTestCase(0x20b8310e, 64, AArch64Assembler.SIMDElementSize.Byte, AArch64.v0, AArch64.v1));
|
||||
assertWrapper(new AddvEncodingTestCase(0x42b8314e, 128, AArch64Assembler.SIMDElementSize.Byte, AArch64.v2, AArch64.v2));
|
||||
assertWrapper(new AddvEncodingTestCase(0xd2ba710e, 64, AArch64Assembler.SIMDElementSize.HalfWord, AArch64.v18, AArch64.v22));
|
||||
assertWrapper(new AddvEncodingTestCase(0x77ba714e, 128, AArch64Assembler.SIMDElementSize.HalfWord, AArch64.v23, AArch64.v19));
|
||||
assertWrapper(new AddvEncodingTestCase(0x18bbb14e, 128, AArch64Assembler.SIMDElementSize.Word, AArch64.v24, AArch64.v24));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testAddvWithInvalidSizeLaneCombo() {
|
||||
new AddvEncodingTestCase(invalidInstructionCode, 64, AArch64Assembler.SIMDElementSize.Word, AArch64.v0, AArch64.v1);
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testAddvWithInvalidDataSize() {
|
||||
new AddvEncodingTestCase(invalidInstructionCode, 32, AArch64Assembler.SIMDElementSize.Word, AArch64.v0, AArch64.v1);
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testAddvWithInvalidLane() {
|
||||
new AddvEncodingTestCase(invalidInstructionCode, 128, AArch64Assembler.SIMDElementSize.DoubleWord, AArch64.v0, AArch64.v1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUmov() {
|
||||
assertWrapper(new UmovEncodingTestCase(0x1f3c084e, 64, AArch64.r31, 0, AArch64.v0));
|
||||
assertWrapper(new UmovEncodingTestCase(0xe13f184e, 64, AArch64.r1, 1, AArch64.v31));
|
||||
|
||||
assertWrapper(new UmovEncodingTestCase(0x5d3c040e, 32, AArch64.r29, 0, AArch64.v2));
|
||||
assertWrapper(new UmovEncodingTestCase(0x833f1c0e, 32, AArch64.r3, 3, AArch64.v28));
|
||||
|
||||
assertWrapper(new UmovEncodingTestCase(0x4b3d020e, 16, AArch64.r11, 0, AArch64.v10));
|
||||
assertWrapper(new UmovEncodingTestCase(0x893d1e0e, 16, AArch64.r9, 7, AArch64.v12));
|
||||
|
||||
assertWrapper(new UmovEncodingTestCase(0x0d3d010e, 8, AArch64.r13, 0, AArch64.v8));
|
||||
assertWrapper(new UmovEncodingTestCase(0xc73d1f0e, 8, AArch64.r7, 15, AArch64.v14));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testUmovInvalidSrcIdx() {
|
||||
new UmovEncodingTestCase(invalidInstructionCode, 64, AArch64.r0, 2, AArch64.v0);
|
||||
}
|
||||
|
||||
@Test(expected = GraalError.class)
|
||||
@SuppressWarnings("unused")
|
||||
public void testUmovInvalidDataSize() {
|
||||
new UmovEncodingTestCase(invalidInstructionCode, 31, AArch64.r0, 3, AArch64.v0);
|
||||
}
|
||||
}
|
||||
@ -1,311 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited. 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.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class AArch64LoadStoreMergingAssemblerTest extends GraalTest {
|
||||
private Register base;
|
||||
private Register rt1;
|
||||
private Register rt2;
|
||||
|
||||
@Before
|
||||
public void checkAArch64() {
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
assumeTrue("skipping non AArch64 specific test", target.arch instanceof AArch64);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupEnvironment() {
|
||||
base = AArch64.sp;
|
||||
rt1 = AArch64.r1;
|
||||
rt2 = AArch64.r2;
|
||||
}
|
||||
|
||||
private abstract static class AArch64LoadStoreCodeGen {
|
||||
protected AArch64MacroAssembler masm1;
|
||||
protected AArch64MacroAssembler masm2;
|
||||
|
||||
AArch64LoadStoreCodeGen() {
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
masm1 = new AArch64MacroAssembler(target);
|
||||
masm2 = new AArch64MacroAssembler(target);
|
||||
}
|
||||
|
||||
void emitScaledImmLdr(int size, Register rt, Register base, int imm12) {
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12);
|
||||
masm2.ldr(size, rt, address);
|
||||
}
|
||||
|
||||
void emitUnscaledImmLdr(int size, Register rt, Register base, int imm9) {
|
||||
AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9);
|
||||
masm2.ldr(size, rt, address1);
|
||||
}
|
||||
|
||||
void emitScaledImmStr(int size, Register rt, Register base, int imm12) {
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12);
|
||||
masm2.str(size, rt, address);
|
||||
}
|
||||
|
||||
void emitUnscaledImmStr(int size, Register rt, Register base, int imm9) {
|
||||
AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9);
|
||||
masm2.str(size, rt, address1);
|
||||
}
|
||||
|
||||
void emitScaledLdp(int size, Register rt1, Register rt2, Register base, int imm7) {
|
||||
AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7);
|
||||
masm1.ldp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitScaledStp(int size, Register rt1, Register rt2, Register base, int imm7) {
|
||||
AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7);
|
||||
masm1.stp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitUnscaledLdp(int size, Register rt1, Register rt2, Register base, int imm) {
|
||||
AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm);
|
||||
masm1.ldp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitUnscaledStp(int size, Register rt1, Register rt2, Register base, int imm) {
|
||||
AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm);
|
||||
masm1.stp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
abstract void checkAssembly();
|
||||
}
|
||||
|
||||
private static class AArch64LoadStoreMergingCodeGen extends AArch64LoadStoreCodeGen {
|
||||
AArch64LoadStoreMergingCodeGen() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkAssembly() {
|
||||
byte[] expected = masm1.close(false);
|
||||
byte[] actual = masm2.close(false);
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad64BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(64, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 5);
|
||||
codeGen.emitScaledLdp(64, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad32BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 5);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 4);
|
||||
codeGen.emitScaledLdp(32, rt2, rt1, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore64BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmStr(64, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(64, rt2, base, 5);
|
||||
codeGen.emitScaledStp(64, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore32BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmStr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(32, rt2, base, 5);
|
||||
codeGen.emitScaledStp(32, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad64BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(64, rt1, base, -32);
|
||||
codeGen.emitUnscaledImmLdr(64, rt2, base, -24);
|
||||
codeGen.emitUnscaledLdp(64, rt1, rt2, base, -32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad32BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 248);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 252);
|
||||
codeGen.emitUnscaledLdp(32, rt1, rt2, base, 248);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore64BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(64, rt1, base, 32);
|
||||
codeGen.emitUnscaledImmStr(64, rt2, base, 40);
|
||||
codeGen.emitUnscaledStp(64, rt1, rt2, base, 32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore32BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(32, rt1, base, 32);
|
||||
codeGen.emitUnscaledImmStr(32, rt2, base, 36);
|
||||
codeGen.emitUnscaledStp(32, rt1, rt2, base, 32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadUnscaledScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 48);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 13);
|
||||
codeGen.emitScaledLdp(32, rt1, rt2, base, 12);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadScaledUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 13);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 48);
|
||||
codeGen.emitUnscaledLdp(32, rt2, rt1, base, 48);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadMaxAlignedOffset() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(64, rt1, base, 62);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 63);
|
||||
codeGen.emitScaledLdp(64, rt1, rt2, base, 62);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreMinAlignedOffest() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(32, rt1, base, -256);
|
||||
codeGen.emitUnscaledImmStr(32, rt2, base, -252);
|
||||
codeGen.emitUnscaledStp(32, rt1, rt2, base, -256);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
// All the following tests are the negative ones that ldr/str will not be merged to ldp/stp.
|
||||
private static class AArch64LoadStoreNotMergingCodeGen extends AArch64LoadStoreCodeGen {
|
||||
AArch64LoadStoreNotMergingCodeGen() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkAssembly() {
|
||||
boolean isMerged = masm2.isImmLoadStoreMerged();
|
||||
masm2.close(false);
|
||||
Assert.assertFalse(isMerged);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentBase() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, AArch64.r3, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentSize() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameRt() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDependencyLdrs() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, rt1, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, rt1, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnalignedOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 34);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 38);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncontinuousOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 6);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreaterThanMaxOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 66);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 67);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLdrStr() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(32, rt2, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
}
|
||||
@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited and 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class AArch64MoveConstantTest extends GraalTest {
|
||||
|
||||
private AArch64MacroAssembler masm;
|
||||
private TestProtectedAssembler asm;
|
||||
private Register dst;
|
||||
private Register zr;
|
||||
|
||||
@Before
|
||||
public void setupEnvironment() {
|
||||
// Setup AArch64 MacroAssembler and Assembler.
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
masm = new AArch64MacroAssembler(target);
|
||||
asm = new TestProtectedAssembler(target);
|
||||
dst = AArch64.r10;
|
||||
zr = AArch64.zr;
|
||||
}
|
||||
|
||||
/**
|
||||
* MacroAssembler behavior test for 32-bit constant move.
|
||||
*/
|
||||
@Test
|
||||
public void testMoveIntZero() {
|
||||
masm.mov(dst, 0); // zero is specially handled by OR(dst, zr, zr).
|
||||
asm.orr(32, dst, zr, zr, AArch64Assembler.ShiftType.LSL, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntLogicalImm() {
|
||||
masm.mov(dst, 0x5555_5555); // 0b01010101...0101 is a 32-bit logical immediate.
|
||||
asm.orr(32, dst, zr, 0x5555_5555);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntMinusOne() {
|
||||
masm.mov(dst, -1);
|
||||
asm.movn(32, dst, 0, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntHighZero() {
|
||||
masm.mov(dst, 0x0000_1234);
|
||||
asm.movz(32, dst, 0x1234, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntLowZero() {
|
||||
masm.mov(dst, 0x5678_0000);
|
||||
asm.movz(32, dst, 0x5678, 16);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntHighNeg() {
|
||||
masm.mov(dst, 0xFFFF_CAFE);
|
||||
asm.movn(32, dst, 0xCAFE ^ 0xFFFF, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntLowNeg() {
|
||||
masm.mov(dst, 0xBABE_FFFF);
|
||||
asm.movn(32, dst, 0xBABE ^ 0xFFFF, 16);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveIntCommon() {
|
||||
masm.mov(dst, 0x1357_BEEF);
|
||||
asm.movz(32, dst, 0xBEEF, 0);
|
||||
asm.movk(32, dst, 0x1357, 16);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
/**
|
||||
* MacroAssembler behavior test for 64-bit constant move.
|
||||
*/
|
||||
@Test
|
||||
public void testMoveLongZero() {
|
||||
masm.mov(dst, 0L); // zero is specially handled by OR(dst, zr, zr).
|
||||
asm.orr(64, dst, zr, zr, AArch64Assembler.ShiftType.LSL, 0);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongLogicalImm() {
|
||||
masm.mov(dst, 0x3333_3333_3333_3333L); // 0b00110011...0011 is a 64-bit logical immediate.
|
||||
asm.orr(64, dst, zr, 0x3333_3333_3333_3333L);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongSignExtendedLogicalImm() {
|
||||
masm.mov(dst, 0xFFFF_FFFF_8888_8888L); // 0x88888888 is a 32-bit logical immediate.
|
||||
asm.orr(32, dst, zr, 0x8888_8888);
|
||||
asm.sbfm(64, dst, dst, 0, 31);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongWithTwoZeros() {
|
||||
masm.mov(dst, 0x1357_0000_ABCD_0000L);
|
||||
asm.movz(64, dst, 0xABCD, 16);
|
||||
asm.movk(64, dst, 0x1357, 48);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongWithTwoNegs() {
|
||||
masm.mov(dst, 0x2222_FFFF_FFFF_7777L);
|
||||
asm.movn(64, dst, 0x7777 ^ 0xFFFF, 0);
|
||||
asm.movk(64, dst, 0x2222, 48);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongWithOneZero() {
|
||||
masm.mov(dst, 0x0000_6666_5555_4444L);
|
||||
asm.movz(64, dst, 0x4444, 0);
|
||||
asm.movk(64, dst, 0x5555, 16);
|
||||
asm.movk(64, dst, 0x6666, 32);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongWithOneNeg() {
|
||||
masm.mov(dst, 0xDDDD_CCCC_BBBB_FFFFL);
|
||||
asm.movn(64, dst, 0xBBBB ^ 0xFFFF, 16);
|
||||
asm.movk(64, dst, 0xCCCC, 32);
|
||||
asm.movk(64, dst, 0xDDDD, 48);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveLongCommon() {
|
||||
masm.mov(dst, 0x3D38_2A05_B001_1942L);
|
||||
asm.movz(64, dst, 0x1942, 0);
|
||||
asm.movk(64, dst, 0xB001, 16);
|
||||
asm.movk(64, dst, 0x2A05, 32);
|
||||
asm.movk(64, dst, 0x3D38, 48);
|
||||
compareAssembly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares assembly generated by the macro assembler to the hand-generated assembly.
|
||||
*/
|
||||
private void compareAssembly() {
|
||||
byte[] expected = asm.close(true);
|
||||
byte[] actual = masm.close(true);
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare constant values with corresponding hex strings.
|
||||
*/
|
||||
@Test
|
||||
public void testConstantHexRepresentation() {
|
||||
checkInt(0, "0");
|
||||
checkInt(-1, "FFFFFFFF");
|
||||
checkInt(0x4B95_0000, "4B950000");
|
||||
checkInt(0xEE2A, "EE2A");
|
||||
checkInt(0x31C2_FFFF, "31C2FFFF");
|
||||
checkInt(0xFFFF_5678, "FFFF5678");
|
||||
checkInt(0xB39F_01CC, "B39F01CC");
|
||||
checkLong(0L, "0");
|
||||
checkLong(-1L, "FFFFFFFFFFFFFFFF");
|
||||
checkLong(0x94DDL, "94DD");
|
||||
checkLong(0x351C_0000_7B7BL, "351C00007B7B");
|
||||
checkLong(0x9012_ABCD_3333_0000L, "9012ABCD33330000");
|
||||
checkLong(0xFFFFL, "FFFF");
|
||||
checkLong(0xFFFF_0001L, "FFFF0001");
|
||||
checkLong(0xFFFF_9302_FFFF_CDEFL, "FFFF9302FFFFCDEF");
|
||||
checkLong(0x102A_FFFF_FFFF_FFFFL, "102AFFFFFFFFFFFF");
|
||||
checkLong(0x9E8C_3A50_0BC9_44F8L, "9E8C3A500BC944F8");
|
||||
}
|
||||
|
||||
private static void checkInt(int value, String hexString) {
|
||||
assertTrue(Integer.toHexString(value).toUpperCase().equals(hexString), "Expected: " + hexString);
|
||||
}
|
||||
|
||||
private static void checkLong(long value, String hexString) {
|
||||
assertTrue(Long.toHexString(value).toUpperCase().equals(hexString), "Expected: " + hexString);
|
||||
}
|
||||
}
|
||||
@ -1,557 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import org.graalvm.compiler.asm.AbstractAddress;
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
/**
|
||||
* Cheat so that we can test protected functions of assembler.
|
||||
*/
|
||||
class TestProtectedAssembler extends AArch64Assembler {
|
||||
|
||||
TestProtectedAssembler(TargetDescription target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cbnz(int size, Register reg, int imm21, int pos) {
|
||||
super.cbnz(size, reg, imm21, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cbz(int size, Register reg, int imm21, int pos) {
|
||||
super.cbz(size, reg, imm21, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ands(int size, Register dst, Register src, long bimm) {
|
||||
super.ands(size, dst, src, bimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void b(ConditionFlag condition, int imm21) {
|
||||
super.b(condition, imm21);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void b(ConditionFlag condition, int imm21, int pos) {
|
||||
super.b(condition, imm21, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cbnz(int size, Register reg, int imm21) {
|
||||
super.cbnz(size, reg, imm21);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cbz(int size, Register reg, int imm21) {
|
||||
super.cbz(size, reg, imm21);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void b(int imm28) {
|
||||
super.b(imm28);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void b(int imm28, int pos) {
|
||||
super.b(imm28, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bl(int imm28) {
|
||||
super.bl(imm28);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blr(Register reg) {
|
||||
super.blr(reg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void br(Register reg) {
|
||||
super.br(reg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ret(Register reg) {
|
||||
super.ret(reg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ldr(int srcSize, Register rt, AArch64Address address) {
|
||||
super.ldr(srcSize, rt, address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
|
||||
super.ldrs(targetSize, srcSize, rt, address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void str(int destSize, Register rt, AArch64Address address) {
|
||||
super.str(destSize, rt, address);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ldxr(int size, Register rt, Register rn) {
|
||||
super.ldxr(size, rt, rn);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stxr(int size, Register rs, Register rt, Register rn) {
|
||||
super.stxr(size, rs, rt, rn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ldaxr(int size, Register rt, Register rn) {
|
||||
super.ldaxr(size, rt, rn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stlxr(int size, Register rs, Register rt, Register rn) {
|
||||
super.stlxr(size, rs, rt, rn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adr(Register dst, int imm21) {
|
||||
super.adr(dst, imm21);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void add(int size, Register dst, Register src, int aimm) {
|
||||
super.add(size, dst, src, aimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adds(int size, Register dst, Register src, int aimm) {
|
||||
super.adds(size, dst, src, aimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sub(int size, Register dst, Register src, int aimm) {
|
||||
super.sub(size, dst, src, aimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void subs(int size, Register dst, Register src, int aimm) {
|
||||
super.subs(size, dst, src, aimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void and(int size, Register dst, Register src, long bimm) {
|
||||
super.and(size, dst, src, bimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eor(int size, Register dst, Register src, long bimm) {
|
||||
super.eor(size, dst, src, bimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void orr(int size, Register dst, Register src, long bimm) {
|
||||
super.orr(size, dst, src, bimm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
|
||||
super.movz(size, dst, uimm16, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
|
||||
super.movn(size, dst, uimm16, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void movk(int size, Register dst, int uimm16, int pos) {
|
||||
super.movk(size, dst, uimm16, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bfm(int size, Register dst, Register src, int r, int s) {
|
||||
super.bfm(size, dst, src, r, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ubfm(int size, Register dst, Register src, int r, int s) {
|
||||
super.ubfm(size, dst, src, r, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sbfm(int size, Register dst, Register src, int r, int s) {
|
||||
super.sbfm(size, dst, src, r, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
|
||||
super.extr(size, dst, src1, src2, lsb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.adds(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.subs(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.add(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
|
||||
super.sub(size, dst, src1, src2, shiftType, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
super.add(size, dst, src1, src2, extendType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
super.adds(size, dst, src1, src2, extendType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
super.sub(size, dst, src1, src2, extendType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
|
||||
super.subs(size, dst, src1, src2, extendType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.and(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.ands(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.bic(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.bics(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.eon(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.eor(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.orr(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
|
||||
super.orn(size, dst, src1, src2, shiftType, shiftAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void asr(int size, Register dst, Register src1, Register src2) {
|
||||
super.asr(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void lsl(int size, Register dst, Register src1, Register src2) {
|
||||
super.lsl(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void lsr(int size, Register dst, Register src1, Register src2) {
|
||||
super.lsr(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void rorv(int size, Register dst, Register src1, Register src2) {
|
||||
super.rorv(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cls(int size, Register dst, Register src) {
|
||||
super.cls(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clz(int size, Register dst, Register src) {
|
||||
super.clz(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rbit(int size, Register dst, Register src) {
|
||||
super.rbit(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rev(int size, Register dst, Register src) {
|
||||
super.rev(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
|
||||
super.csel(size, dst, src1, src2, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
|
||||
super.csneg(size, dst, src1, src2, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
|
||||
super.csinc(size, dst, src1, src2, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
|
||||
super.madd(size, dst, src1, src2, src3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
|
||||
super.msub(size, dst, src1, src2, src3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sdiv(int size, Register dst, Register src1, Register src2) {
|
||||
super.sdiv(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void udiv(int size, Register dst, Register src1, Register src2) {
|
||||
super.udiv(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fldr(int size, Register rt, AArch64Address address) {
|
||||
super.fldr(size, rt, address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fstr(int size, Register rt, AArch64Address address) {
|
||||
super.fstr(size, rt, address);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmov(int size, Register dst, Register src) {
|
||||
super.fmov(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmovFpu2Cpu(int size, Register dst, Register src) {
|
||||
super.fmovFpu2Cpu(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmovCpu2Fpu(int size, Register dst, Register src) {
|
||||
super.fmovCpu2Fpu(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmov(int size, Register dst, double imm) {
|
||||
super.fmov(size, dst, imm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fcvt(int srcSize, Register dst, Register src) {
|
||||
super.fcvt(srcSize, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
|
||||
super.fcvtzs(targetSize, srcSize, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
|
||||
super.scvtf(targetSize, srcSize, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void frintz(int size, Register dst, Register src) {
|
||||
super.frintz(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fabs(int size, Register dst, Register src) {
|
||||
super.fabs(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fneg(int size, Register dst, Register src) {
|
||||
super.fneg(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fsqrt(int size, Register dst, Register src) {
|
||||
super.fsqrt(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fadd(int size, Register dst, Register src1, Register src2) {
|
||||
super.fadd(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fsub(int size, Register dst, Register src1, Register src2) {
|
||||
super.fsub(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fmul(int size, Register dst, Register src1, Register src2) {
|
||||
super.fmul(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fdiv(int size, Register dst, Register src1, Register src2) {
|
||||
super.fdiv(size, dst, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
|
||||
super.fmadd(size, dst, src1, src2, src3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
|
||||
super.fmsub(size, dst, src1, src2, src3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fcmp(int size, Register src1, Register src2) {
|
||||
super.fcmp(size, src1, src2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
|
||||
super.fccmp(size, src1, src2, uimm4, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fcmpZero(int size, Register src) {
|
||||
super.fcmpZero(size, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
|
||||
super.fcsel(size, dst, src1, src2, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hlt(int uimm16) {
|
||||
super.hlt(uimm16);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void brk(int uimm16) {
|
||||
super.brk(uimm16);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hint(SystemHint hint) {
|
||||
super.hint(hint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clrex() {
|
||||
super.clrex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmb(BarrierKind barrierKind) {
|
||||
super.dmb(barrierKind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void align(int modulus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jmp(Label l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void patchJumpTarget(int branch, int jumpTarget) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAddress makeAddress(Register base, int displacement) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAddress getPlaceholder(int instructionStartPosition) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureUniquePC() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cnt(int size, Register dst, Register src) {
|
||||
super.cnt(size, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addv(int size, SIMDElementSize laneWidth, Register dst, Register src) {
|
||||
super.addv(size, laneWidth, dst, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void umov(int size, Register dst, int srcIdx, Register src) {
|
||||
super.umov(size, dst, srcIdx, src);
|
||||
}
|
||||
}
|
||||
@ -1,388 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64;
|
||||
|
||||
import static jdk.vm.ci.aarch64.AArch64.zr;
|
||||
|
||||
import org.graalvm.compiler.asm.AbstractAddress;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
|
||||
/**
|
||||
* Represents an address in target machine memory, specified using one of the different addressing
|
||||
* modes of the AArch64 ISA. - Base register only - Base register + immediate or register with
|
||||
* shifted offset - Pre-indexed: base + immediate offset are written back to base register, value
|
||||
* used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are
|
||||
* written back to base register, value used in instruction is base only - Literal: PC + 19-bit
|
||||
* signed word aligned offset
|
||||
* <p>
|
||||
* Not all addressing modes are supported for all instructions.
|
||||
*/
|
||||
public final class AArch64Address extends AbstractAddress {
|
||||
// Placeholder for addresses that get patched later.
|
||||
public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0);
|
||||
|
||||
public enum AddressingMode {
|
||||
/**
|
||||
* base + uimm12 << log2(memory_transfer_size).
|
||||
*/
|
||||
IMMEDIATE_SCALED,
|
||||
/**
|
||||
* base + imm9.
|
||||
*/
|
||||
IMMEDIATE_UNSCALED,
|
||||
/**
|
||||
* base.
|
||||
*/
|
||||
BASE_REGISTER_ONLY,
|
||||
/**
|
||||
* base + offset [<< log2(memory_transfer_size)].
|
||||
*/
|
||||
REGISTER_OFFSET,
|
||||
/**
|
||||
* base + extend(offset) [<< log2(memory_transfer_size)].
|
||||
*/
|
||||
EXTENDED_REGISTER_OFFSET,
|
||||
/**
|
||||
* PC + imm21 (word aligned).
|
||||
*/
|
||||
PC_LITERAL,
|
||||
/**
|
||||
* address = base. base is updated to base + imm9
|
||||
*/
|
||||
IMMEDIATE_POST_INDEXED,
|
||||
/**
|
||||
* address = base + imm9. base is updated to base + imm9
|
||||
*/
|
||||
IMMEDIATE_PRE_INDEXED,
|
||||
}
|
||||
|
||||
private final Register base;
|
||||
private final Register offset;
|
||||
private final int immediate;
|
||||
/**
|
||||
* Should register offset be scaled or not.
|
||||
*/
|
||||
private final boolean scaled;
|
||||
private final AArch64Assembler.ExtendType extendType;
|
||||
private final AddressingMode addressingMode;
|
||||
|
||||
/**
|
||||
* General address generation mechanism. Accepted values for all parameters depend on the
|
||||
* addressingMode. Null is never accepted for a register, if an addressMode doesn't use a
|
||||
* register the register has to be the zero-register. extendType has to be null for every
|
||||
* addressingMode except EXTENDED_REGISTER_OFFSET.
|
||||
*/
|
||||
public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) {
|
||||
return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param imm9 Signed 9-bit immediate value.
|
||||
* @return an address specifying a post-indexed immediate address pointing to base. After
|
||||
* ldr/str instruction, base is updated to point to base + imm9
|
||||
*/
|
||||
public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) {
|
||||
return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param imm9 Signed 9-bit immediate value.
|
||||
* @return an address specifying a pre-indexed immediate address pointing to base + imm9. After
|
||||
* ldr/str instruction, base is updated to point to base + imm9
|
||||
*/
|
||||
public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) {
|
||||
return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param imm12 Unsigned 12-bit immediate value. This is scaled by the word access size. This
|
||||
* means if this address is used to load/store a word, the immediate is shifted by 2
|
||||
* (log2Ceil(4)).
|
||||
* @return an address specifying a signed address of the form base + imm12 <<
|
||||
* log2(memory_transfer_size).
|
||||
*/
|
||||
public static AArch64Address createScaledImmediateAddress(Register base, int imm12) {
|
||||
return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param imm9 Signed 9-bit immediate value.
|
||||
* @return an address specifying an unscaled immediate address of the form base + imm9
|
||||
*/
|
||||
public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) {
|
||||
return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base May not be null or the zero register.
|
||||
* @return an address specifying the address pointed to by base.
|
||||
*/
|
||||
public static AArch64Address createBaseRegisterOnlyAddress(Register base) {
|
||||
return createRegisterOffsetAddress(base, zr, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param offset Register specifying some offset, optionally scaled by the memory_transfer_size.
|
||||
* May not be null or the stackpointer.
|
||||
* @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
|
||||
* @return an address specifying a register offset address of the form base + offset [<< log2
|
||||
* (memory_transfer_size)]
|
||||
*/
|
||||
public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) {
|
||||
return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param imm7 Signed 7-bit immediate value.
|
||||
* @return an address specifying an unscaled immediate address of the form base + imm7
|
||||
*/
|
||||
public static AArch64Address createPairUnscaledImmediateAddress(Register base, int imm7) {
|
||||
return new AArch64Address(base, zr, imm7, false, null, AddressingMode.IMMEDIATE_UNSCALED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param base may not be null or the zero-register.
|
||||
* @param offset Word register specifying some offset, optionally scaled by the
|
||||
* memory_transfer_size. May not be null or the stackpointer.
|
||||
* @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
|
||||
* @param extendType Describes whether register is zero- or sign-extended. May not be null.
|
||||
* @return an address specifying an extended register offset of the form base +
|
||||
* extendType(offset) [<< log2(memory_transfer_size)]
|
||||
*/
|
||||
public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) {
|
||||
return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param imm21 Signed 21-bit offset, word aligned.
|
||||
* @return AArch64Address specifying a PC-literal address of the form PC + offset
|
||||
*/
|
||||
public static AArch64Address createPcLiteralAddress(int imm21) {
|
||||
return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL);
|
||||
}
|
||||
|
||||
private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) {
|
||||
this.base = base;
|
||||
this.offset = offset;
|
||||
if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) {
|
||||
this.addressingMode = AddressingMode.BASE_REGISTER_ONLY;
|
||||
} else {
|
||||
this.addressingMode = addressingMode;
|
||||
}
|
||||
this.immediate = immediate;
|
||||
this.scaled = scaled;
|
||||
this.extendType = extendType;
|
||||
assert verify();
|
||||
}
|
||||
|
||||
private boolean verify() {
|
||||
assert addressingMode != null;
|
||||
assert base.getRegisterCategory().equals(AArch64.CPU);
|
||||
assert offset.getRegisterCategory().equals(AArch64.CPU);
|
||||
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_SCALED:
|
||||
assert !base.equals(zr);
|
||||
assert offset.equals(zr);
|
||||
assert extendType == null;
|
||||
assert NumUtil.isUnsignedNbit(12, immediate);
|
||||
break;
|
||||
case IMMEDIATE_UNSCALED:
|
||||
assert !base.equals(zr);
|
||||
assert offset.equals(zr);
|
||||
assert extendType == null;
|
||||
assert NumUtil.isSignedNbit(9, immediate);
|
||||
break;
|
||||
case BASE_REGISTER_ONLY:
|
||||
assert !base.equals(zr);
|
||||
assert offset.equals(zr);
|
||||
assert extendType == null;
|
||||
assert immediate == 0;
|
||||
break;
|
||||
case REGISTER_OFFSET:
|
||||
assert !base.equals(zr);
|
||||
assert offset.getRegisterCategory().equals(AArch64.CPU);
|
||||
assert extendType == null;
|
||||
assert immediate == 0;
|
||||
break;
|
||||
case EXTENDED_REGISTER_OFFSET:
|
||||
assert !base.equals(zr);
|
||||
assert offset.getRegisterCategory().equals(AArch64.CPU);
|
||||
assert (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW);
|
||||
assert immediate == 0;
|
||||
break;
|
||||
case PC_LITERAL:
|
||||
assert base.equals(zr);
|
||||
assert offset.equals(zr);
|
||||
assert extendType == null;
|
||||
assert NumUtil.isSignedNbit(21, immediate);
|
||||
assert ((immediate & 0x3) == 0);
|
||||
break;
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
assert !base.equals(zr);
|
||||
assert offset.equals(zr);
|
||||
assert extendType == null;
|
||||
assert NumUtil.isSignedNbit(9, immediate);
|
||||
break;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Register getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
public Register getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return immediate in correct representation for the given addressing mode. For example in
|
||||
* case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
|
||||
* as the 9-bit signed representation.
|
||||
*/
|
||||
public int getImmediate() {
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_UNSCALED:
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
// 9-bit signed value
|
||||
assert NumUtil.isSignedNbit(9, immediate);
|
||||
return immediate & NumUtil.getNbitNumberInt(9);
|
||||
case IMMEDIATE_SCALED:
|
||||
// Unsigned value can be returned as-is.
|
||||
assert NumUtil.isUnsignedNbit(12, immediate);
|
||||
return immediate;
|
||||
case PC_LITERAL:
|
||||
// 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
|
||||
assert NumUtil.isSignedNbit(19, immediate >> 2);
|
||||
return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Raw immediate as a 32-bit signed value.
|
||||
*/
|
||||
public int getImmediateRaw() {
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_UNSCALED:
|
||||
case IMMEDIATE_SCALED:
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
case PC_LITERAL:
|
||||
return immediate;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isScaled() {
|
||||
return scaled;
|
||||
}
|
||||
|
||||
public AArch64Assembler.ExtendType getExtendType() {
|
||||
return extendType;
|
||||
}
|
||||
|
||||
public AddressingMode getAddressingMode() {
|
||||
return addressingMode;
|
||||
}
|
||||
|
||||
public String toString(int log2TransferSize) {
|
||||
int shiftVal = scaled ? log2TransferSize : 0;
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_SCALED:
|
||||
return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize);
|
||||
case IMMEDIATE_UNSCALED:
|
||||
return String.format("[X%d, %d]", base.encoding, immediate);
|
||||
case BASE_REGISTER_ONLY:
|
||||
return String.format("[X%d]", base.encoding);
|
||||
case EXTENDED_REGISTER_OFFSET:
|
||||
if (shiftVal != 0) {
|
||||
return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal);
|
||||
} else {
|
||||
return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name());
|
||||
}
|
||||
case REGISTER_OFFSET:
|
||||
if (shiftVal != 0) {
|
||||
return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal);
|
||||
} else {
|
||||
// LSL 0 may be optional, but still encoded differently so we always leave it
|
||||
// off
|
||||
return String.format("[X%d, X%d]", base.encoding, offset.encoding);
|
||||
}
|
||||
case PC_LITERAL:
|
||||
return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate);
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
return String.format("[X%d],%d", base.encoding, immediate);
|
||||
case IMMEDIATE_PRE_INDEXED:
|
||||
return String.format("[X%d,%d]!", base.encoding, immediate);
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an address into Register r.
|
||||
*
|
||||
* @param masm the macro assembler.
|
||||
* @param r general purpose register. May not be null.
|
||||
*/
|
||||
public void lea(AArch64MacroAssembler masm, Register r) {
|
||||
switch (addressingMode) {
|
||||
case IMMEDIATE_UNSCALED:
|
||||
if (immediate == 0 && base.equals(r)) { // it's a nop
|
||||
break;
|
||||
}
|
||||
masm.add(64, r, base, immediate);
|
||||
break;
|
||||
case REGISTER_OFFSET:
|
||||
masm.add(64, r, base, offset);
|
||||
break;
|
||||
case PC_LITERAL: {
|
||||
masm.mov(r, getImmediate());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,272 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64.test;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler;
|
||||
import org.graalvm.compiler.asm.test.AssemblerTest;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64.CPUFeature;
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
public class BitOpsTest extends AssemblerTest {
|
||||
private static boolean lzcntSupported;
|
||||
private static boolean tzcntSupported;
|
||||
|
||||
@Before
|
||||
public void checkAMD64() {
|
||||
assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
|
||||
EnumSet<CPUFeature> features = ((AMD64) codeCache.getTarget().arch).getFeatures();
|
||||
lzcntSupported = features.contains(CPUFeature.LZCNT);
|
||||
tzcntSupported = features.contains(CPUFeature.BMI1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lzcntlTest() {
|
||||
if (lzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
Register arg = asRegister(cc.getArgument(0));
|
||||
LZCNT.emit(asm, DWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("intStub", test, 31, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lzcntlMemTest() {
|
||||
if (lzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = IntField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
LZCNT.emit(asm, DWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
assertReturn("intFieldStub", test, 31, new IntField(1));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lzcntqTest() {
|
||||
if (lzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
Register arg = asRegister(cc.getArgument(0));
|
||||
LZCNT.emit(asm, QWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("longStub", test, 63, 1L);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lzcntqMemTest() {
|
||||
if (lzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = LongField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
LZCNT.emit(asm, QWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
assertReturn("longFieldStub", test, 63, new LongField(1));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tzcntlTest() {
|
||||
if (tzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
Register arg = asRegister(cc.getArgument(0));
|
||||
TZCNT.emit(asm, DWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("intStub", test, 31, 0x8000_0000);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tzcntlMemTest() {
|
||||
if (tzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = IntField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
TZCNT.emit(asm, DWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
assertReturn("intFieldStub", test, 31, new IntField(0x8000_0000));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tzcntqTest() {
|
||||
if (tzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
Register arg = asRegister(cc.getArgument(0));
|
||||
TZCNT.emit(asm, QWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("longStub", test, 63, 0x8000_0000_0000_0000L);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tzcntqMemTest() {
|
||||
if (tzcntSupported) {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = LongField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
TZCNT.emit(asm, QWORD, ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
assertReturn("longFieldStub", test, 63, new LongField(0x8000_0000_0000_0000L));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int intStub(int arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int longStub(long arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static class IntField {
|
||||
public int x;
|
||||
|
||||
IntField(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LongField {
|
||||
public long x;
|
||||
|
||||
LongField(long x) {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int intFieldStub(IntField arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static int longFieldStub(LongField arg) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64.test;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.asm.test.AssemblerTest;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
|
||||
public class IncrementDecrementMacroTest extends AssemblerTest {
|
||||
|
||||
@Before
|
||||
public void checkAMD64() {
|
||||
assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
|
||||
}
|
||||
|
||||
public static class LongField {
|
||||
public long x;
|
||||
|
||||
LongField(long x) {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
|
||||
private static class IncrementCodeGenTest implements CodeGenTest {
|
||||
final int value;
|
||||
|
||||
IncrementCodeGenTest(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = LongField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
asm.incrementq(arg, value);
|
||||
asm.movq(ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertIncrement(long initValue, int increment) {
|
||||
assertReturn("longFieldStubIncrement", new IncrementCodeGenTest(increment), initValue + increment, new LongField(initValue));
|
||||
}
|
||||
|
||||
private void assertIncrements(int increment) {
|
||||
assertIncrement(0x4242_4242_4242_4242L, increment);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static long longFieldStubIncrement(LongField arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static class DecrementCodeGenTest implements CodeGenTest {
|
||||
final int value;
|
||||
|
||||
DecrementCodeGenTest(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
try {
|
||||
Field f = LongField.class.getDeclaredField("x");
|
||||
AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
|
||||
asm.decrementq(arg, value);
|
||||
asm.movq(ret, arg);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to generate field access:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertDecrement(long initValue, int increment) {
|
||||
assertReturn("longFieldStubDecrement", new DecrementCodeGenTest(increment), initValue - increment, new LongField(initValue));
|
||||
}
|
||||
|
||||
private void assertDecrements(int increment) {
|
||||
assertDecrement(0x4242_4242_4242_4242L, increment);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static long longFieldStubDecrement(LongField arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest0() {
|
||||
int increment = 0;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest1() {
|
||||
int increment = 1;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest2() {
|
||||
int increment = 2;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest3() {
|
||||
int increment = Integer.MAX_VALUE;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest4() {
|
||||
int increment = Integer.MIN_VALUE;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest5() {
|
||||
int increment = -1;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest6() {
|
||||
int increment = -2;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementMemTest7() {
|
||||
int increment = -0x1000_0000;
|
||||
assertIncrements(increment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest0() {
|
||||
int decrement = 0;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest1() {
|
||||
int decrement = 1;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest2() {
|
||||
int decrement = 2;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest3() {
|
||||
int decrement = Integer.MAX_VALUE;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest4() {
|
||||
int decrement = Integer.MIN_VALUE;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest5() {
|
||||
int decrement = -1;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest6() {
|
||||
int decrement = -2;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementMemTest7() {
|
||||
int decrement = -0x1000_0000;
|
||||
assertDecrements(decrement);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64.test;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.asm.test.AssemblerTest;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.code.DataSection.Data;
|
||||
import org.graalvm.compiler.code.DataSection.RawData;
|
||||
import org.graalvm.compiler.code.DataSection.SerializableData;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.code.site.DataSectionReference;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
public class SimpleAssemblerTest extends AssemblerTest {
|
||||
|
||||
@Before
|
||||
public void checkAMD64() {
|
||||
assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intTest() {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64Assembler asm = new AMD64Assembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Int);
|
||||
asm.movl(ret, 8472);
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("intStub", test, 8472);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleTest() {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Double);
|
||||
Data data = new SerializableData(JavaConstant.forDouble(84.72), 8);
|
||||
DataSectionReference ref = compResult.getDataSection().insertData(data);
|
||||
compResult.recordDataPatch(asm.position(), ref);
|
||||
asm.movdbl(ret, asm.getPlaceholder(-1));
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("doubleStub", test, 84.72);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rawDoubleTest() {
|
||||
CodeGenTest test = new CodeGenTest() {
|
||||
|
||||
@Override
|
||||
public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
|
||||
AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
|
||||
Register ret = registerConfig.getReturnRegister(JavaKind.Double);
|
||||
|
||||
byte[] rawBytes = new byte[8];
|
||||
ByteBuffer.wrap(rawBytes).order(ByteOrder.nativeOrder()).putDouble(84.72);
|
||||
Data data = new RawData(rawBytes, 8);
|
||||
DataSectionReference ref = compResult.getDataSection().insertData(data);
|
||||
compResult.recordDataPatch(asm.position(), ref);
|
||||
asm.movdbl(ret, asm.getPlaceholder(-1));
|
||||
asm.ret(0);
|
||||
return asm.close(true);
|
||||
}
|
||||
};
|
||||
assertReturn("doubleStub", test, 84.72);
|
||||
}
|
||||
|
||||
public static int intStub() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static double doubleStub() {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
import org.graalvm.compiler.asm.AbstractAddress;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.code.CodeUtil;
|
||||
import jdk.vm.ci.code.Register;
|
||||
|
||||
/**
|
||||
* Represents an address in target machine memory, specified via some combination of a base
|
||||
* register, an index register, a displacement and a scale. Note that the base and index registers
|
||||
* may be a variable that will get a register assigned later by the register allocator.
|
||||
*/
|
||||
public final class AMD64Address extends AbstractAddress {
|
||||
|
||||
private final Register base;
|
||||
private final Register index;
|
||||
private final Scale scale;
|
||||
private final int displacement;
|
||||
|
||||
/**
|
||||
* The start of the instruction, i.e., the value that is used as the key for looking up
|
||||
* placeholder patching information. Only used for {@link AMD64Assembler#getPlaceholder
|
||||
* placeholder addresses}.
|
||||
*/
|
||||
final int instructionStartPosition;
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
|
||||
*
|
||||
* @param base the base register
|
||||
*/
|
||||
public AMD64Address(Register base) {
|
||||
this(base, Register.None, Scale.Times1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base register, no scaling and a given
|
||||
* displacement.
|
||||
*
|
||||
* @param base the base register
|
||||
* @param displacement the displacement
|
||||
*/
|
||||
public AMD64Address(Register base, int displacement) {
|
||||
this(base, Register.None, Scale.Times1, displacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base and index registers, scaling and 0
|
||||
* displacement.
|
||||
*
|
||||
* @param base the base register
|
||||
* @param index the index register
|
||||
* @param scale the scaling factor
|
||||
*/
|
||||
public AMD64Address(Register base, Register index, Scale scale) {
|
||||
this(base, index, scale, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AMD64Address} with given base and index registers, scaling and
|
||||
* displacement. This is the most general constructor.
|
||||
*
|
||||
* @param base the base register
|
||||
* @param index the index register
|
||||
* @param scale the scaling factor
|
||||
* @param displacement the displacement
|
||||
*/
|
||||
public AMD64Address(Register base, Register index, Scale scale, int displacement) {
|
||||
this(base, index, scale, displacement, -1);
|
||||
}
|
||||
|
||||
AMD64Address(Register base, Register index, Scale scale, int displacement, int instructionStartPosition) {
|
||||
this.base = base;
|
||||
this.index = index;
|
||||
this.scale = scale;
|
||||
this.displacement = displacement;
|
||||
this.instructionStartPosition = instructionStartPosition;
|
||||
|
||||
assert scale != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A scaling factor used in the SIB addressing mode.
|
||||
*/
|
||||
public enum Scale {
|
||||
Times1(1, 0),
|
||||
Times2(2, 1),
|
||||
Times4(4, 2),
|
||||
Times8(8, 3);
|
||||
|
||||
Scale(int value, int log2) {
|
||||
this.value = value;
|
||||
this.log2 = log2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value (or multiplier) of this scale.
|
||||
*/
|
||||
public final int value;
|
||||
|
||||
/**
|
||||
* The {@linkplain #value value} of this scale log 2.
|
||||
*/
|
||||
public final int log2;
|
||||
|
||||
/**
|
||||
* Creates a {@link Scale} for the scaling factor in {@code scale}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code scale} is an unsupported scaling factor
|
||||
*/
|
||||
public static Scale fromInt(int scale) {
|
||||
switch (scale) {
|
||||
case 1:
|
||||
return Times1;
|
||||
case 2:
|
||||
return Times2;
|
||||
case 4:
|
||||
return Times4;
|
||||
case 8:
|
||||
return Times8;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported SIB addressing mode scaling factor: " + scale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Scale} for the log2 scaling factor {@code shift}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code shift} is an unsupported scaling factor
|
||||
*/
|
||||
public static Scale fromShift(int shift) {
|
||||
switch (shift) {
|
||||
case 0:
|
||||
return Times1;
|
||||
case 1:
|
||||
return Times2;
|
||||
case 2:
|
||||
return Times4;
|
||||
case 3:
|
||||
return Times8;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("Unsupported SIB addressing mode scaling factor: " + (1 << shift));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the scaling factor {@code scale} is supported.
|
||||
*/
|
||||
public static boolean isScaleSupported(int scale) {
|
||||
return CodeUtil.isPowerOf2(scale) && scale <= 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the log2 scaling factor {@code shift} is supported.
|
||||
*/
|
||||
public static boolean isScaleShiftSupported(int shift) {
|
||||
return shift >= 0 && shift <= 3;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("[");
|
||||
String sep = "";
|
||||
if (!getBase().equals(Register.None)) {
|
||||
s.append(getBase());
|
||||
sep = " + ";
|
||||
}
|
||||
if (!getIndex().equals(Register.None)) {
|
||||
s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
|
||||
sep = " + ";
|
||||
}
|
||||
if (getDisplacement() < 0) {
|
||||
s.append(" - ").append(-getDisplacement());
|
||||
} else if (getDisplacement() > 0) {
|
||||
s.append(sep).append(getDisplacement());
|
||||
}
|
||||
s.append("]");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Base register that defines the start of the address computation. If not present, is
|
||||
* denoted by {@link Register#None}.
|
||||
*/
|
||||
public Register getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to
|
||||
* {@link #getBase}. If not present, is denoted by {@link Register#None}.
|
||||
*/
|
||||
public Register getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Scaling factor for indexing, dependent on target operand size.
|
||||
*/
|
||||
public Scale getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Optional additive displacement.
|
||||
*/
|
||||
public int getDisplacement() {
|
||||
return displacement;
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
public class AMD64AsmOptions {
|
||||
public static final boolean UseNormalNop = false;
|
||||
public static final boolean UseAddressNop = true;
|
||||
public static final boolean UseIntelNops = true;
|
||||
public static final boolean UseIncDec = true;
|
||||
public static final boolean UseXmmLoadAndClearUpper = true;
|
||||
public static final boolean UseXmmRegToRegMoveAll = true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,675 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.DEC;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.INC;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
|
||||
import static org.graalvm.compiler.core.common.NumUtil.isByte;
|
||||
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.amd64.AVXKind.AVXSize;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
/**
|
||||
* This class implements commonly used X86 code patterns.
|
||||
*/
|
||||
public class AMD64MacroAssembler extends AMD64Assembler {
|
||||
|
||||
public AMD64MacroAssembler(TargetDescription target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
public AMD64MacroAssembler(TargetDescription target, OptionValues optionValues) {
|
||||
super(target, optionValues);
|
||||
}
|
||||
|
||||
public AMD64MacroAssembler(TargetDescription target, OptionValues optionValues, boolean hasIntelJccErratum) {
|
||||
super(target, optionValues, hasIntelJccErratum);
|
||||
}
|
||||
|
||||
public final void decrementq(Register reg) {
|
||||
decrementq(reg, 1);
|
||||
}
|
||||
|
||||
public final void decrementq(Register reg, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
subq(reg, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
incrementq(reg, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
decq(reg);
|
||||
} else {
|
||||
subq(reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void decrementq(AMD64Address dst, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
subq(dst, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
incrementq(dst, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
decq(dst);
|
||||
} else {
|
||||
subq(dst, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void incrementq(Register reg) {
|
||||
incrementq(reg, 1);
|
||||
}
|
||||
|
||||
public void incrementq(Register reg, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
addq(reg, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
decrementq(reg, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
incq(reg);
|
||||
} else {
|
||||
addq(reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void incrementq(AMD64Address dst, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
addq(dst, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
decrementq(dst, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
incq(dst);
|
||||
} else {
|
||||
addq(dst, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void movptr(Register dst, AMD64Address src) {
|
||||
movq(dst, src);
|
||||
}
|
||||
|
||||
public final void movptr(AMD64Address dst, Register src) {
|
||||
movq(dst, src);
|
||||
}
|
||||
|
||||
public final void movptr(AMD64Address dst, int src) {
|
||||
movslq(dst, src);
|
||||
}
|
||||
|
||||
public final void cmpptr(Register src1, Register src2) {
|
||||
cmpq(src1, src2);
|
||||
}
|
||||
|
||||
public final void cmpptr(Register src1, AMD64Address src2) {
|
||||
cmpq(src1, src2);
|
||||
}
|
||||
|
||||
public final void decrementl(Register reg) {
|
||||
decrementl(reg, 1);
|
||||
}
|
||||
|
||||
public final void decrementl(Register reg, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
subl(reg, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
incrementl(reg, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
decl(reg);
|
||||
} else {
|
||||
subl(reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void decrementl(AMD64Address dst, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
subl(dst, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
incrementl(dst, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
decl(dst);
|
||||
} else {
|
||||
subl(dst, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void incrementl(Register reg, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
addl(reg, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
decrementl(reg, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
incl(reg);
|
||||
} else {
|
||||
addl(reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void incrementl(AMD64Address dst, int value) {
|
||||
if (value == Integer.MIN_VALUE) {
|
||||
addl(dst, value);
|
||||
return;
|
||||
}
|
||||
if (value < 0) {
|
||||
decrementl(dst, -value);
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
if (value == 1 && UseIncDec) {
|
||||
incl(dst);
|
||||
} else {
|
||||
addl(dst, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void movflt(Register dst, Register src) {
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (UseXmmRegToRegMoveAll) {
|
||||
if (isAVX512Register(dst) || isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVAPS.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movaps(dst, src);
|
||||
}
|
||||
} else {
|
||||
if (isAVX512Register(dst) || isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVSS.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movss(dst, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void movflt(Register dst, AMD64Address src) {
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (isAVX512Register(dst)) {
|
||||
VexMoveOp.VMOVSS.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movss(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
public void movflt(AMD64Address dst, Register src) {
|
||||
assert src.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVSS.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movss(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
public void movdbl(Register dst, Register src) {
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (UseXmmRegToRegMoveAll) {
|
||||
if (isAVX512Register(dst) || isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVAPD.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movapd(dst, src);
|
||||
}
|
||||
} else {
|
||||
if (isAVX512Register(dst) || isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVSD.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movsd(dst, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void movdbl(Register dst, AMD64Address src) {
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (UseXmmLoadAndClearUpper) {
|
||||
if (isAVX512Register(dst)) {
|
||||
VexMoveOp.VMOVSD.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movsd(dst, src);
|
||||
}
|
||||
} else {
|
||||
assert !isAVX512Register(dst);
|
||||
movlpd(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
public void movdbl(AMD64Address dst, Register src) {
|
||||
assert src.getRegisterCategory().equals(AMD64.XMM);
|
||||
if (isAVX512Register(src)) {
|
||||
VexMoveOp.VMOVSD.emit(this, AVXSize.XMM, dst, src);
|
||||
} else {
|
||||
movsd(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a
|
||||
* volatile field!
|
||||
*/
|
||||
public final void movlong(AMD64Address dst, long src) {
|
||||
if (NumUtil.isInt(src)) {
|
||||
AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src);
|
||||
} else {
|
||||
AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
|
||||
movl(dst, (int) (src & 0xFFFFFFFF));
|
||||
movl(high, (int) (src >> 32));
|
||||
}
|
||||
}
|
||||
|
||||
public final void setl(ConditionFlag cc, Register dst) {
|
||||
setb(cc, dst);
|
||||
movzbl(dst, dst);
|
||||
}
|
||||
|
||||
public final void setq(ConditionFlag cc, Register dst) {
|
||||
setb(cc, dst);
|
||||
movzbq(dst, dst);
|
||||
}
|
||||
|
||||
public final void flog(Register dest, Register value, boolean base10) {
|
||||
if (base10) {
|
||||
fldlg2();
|
||||
} else {
|
||||
fldln2();
|
||||
}
|
||||
AMD64Address tmp = trigPrologue(value);
|
||||
fyl2x();
|
||||
trigEpilogue(dest, tmp);
|
||||
}
|
||||
|
||||
public final void fsin(Register dest, Register value) {
|
||||
AMD64Address tmp = trigPrologue(value);
|
||||
fsin();
|
||||
trigEpilogue(dest, tmp);
|
||||
}
|
||||
|
||||
public final void fcos(Register dest, Register value) {
|
||||
AMD64Address tmp = trigPrologue(value);
|
||||
fcos();
|
||||
trigEpilogue(dest, tmp);
|
||||
}
|
||||
|
||||
public final void ftan(Register dest, Register value) {
|
||||
AMD64Address tmp = trigPrologue(value);
|
||||
fptan();
|
||||
fstp(0); // ftan pushes 1.0 in addition to the actual result, pop
|
||||
trigEpilogue(dest, tmp);
|
||||
}
|
||||
|
||||
public final void fpop() {
|
||||
ffree(0);
|
||||
fincstp();
|
||||
}
|
||||
|
||||
private AMD64Address trigPrologue(Register value) {
|
||||
assert value.getRegisterCategory().equals(AMD64.XMM);
|
||||
AMD64Address tmp = new AMD64Address(AMD64.rsp);
|
||||
subq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
|
||||
movdbl(tmp, value);
|
||||
fldd(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void trigEpilogue(Register dest, AMD64Address tmp) {
|
||||
assert dest.getRegisterCategory().equals(AMD64.XMM);
|
||||
fstpd(tmp);
|
||||
movdbl(dest, tmp);
|
||||
addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a direct call to a fixed address, which will be patched later during code installation.
|
||||
*
|
||||
* @param align indicates whether the displacement bytes (offset by
|
||||
* {@code callDisplacementOffset}) of this call instruction should be aligned to
|
||||
* {@code wordSize}.
|
||||
* @return where the actual call instruction starts.
|
||||
*/
|
||||
public final int directCall(boolean align, int callDisplacementOffset, int wordSize) {
|
||||
emitAlignmentForDirectCall(align, callDisplacementOffset, wordSize);
|
||||
testAndAlign(5);
|
||||
// After padding to mitigate JCC erratum, the displacement may be unaligned again. The
|
||||
// previous pass is essential because JCC erratum padding may not trigger without the
|
||||
// displacement alignment.
|
||||
emitAlignmentForDirectCall(align, callDisplacementOffset, wordSize);
|
||||
int beforeCall = position();
|
||||
call();
|
||||
return beforeCall;
|
||||
}
|
||||
|
||||
private void emitAlignmentForDirectCall(boolean align, int callDisplacementOffset, int wordSize) {
|
||||
if (align) {
|
||||
// make sure that the displacement word of the call ends up word aligned
|
||||
int offset = position();
|
||||
offset += callDisplacementOffset;
|
||||
int modulus = wordSize;
|
||||
if (offset % modulus != 0) {
|
||||
nop(modulus - offset % modulus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final int indirectCall(Register callReg) {
|
||||
int bytesToEmit = needsRex(callReg) ? 3 : 2;
|
||||
testAndAlign(bytesToEmit);
|
||||
int beforeCall = position();
|
||||
call(callReg);
|
||||
assert beforeCall + bytesToEmit == position();
|
||||
return beforeCall;
|
||||
}
|
||||
|
||||
public final int directCall(long address, Register scratch) {
|
||||
int bytesToEmit = needsRex(scratch) ? 13 : 12;
|
||||
testAndAlign(bytesToEmit);
|
||||
int beforeCall = position();
|
||||
movq(scratch, address);
|
||||
call(scratch);
|
||||
assert beforeCall + bytesToEmit == position();
|
||||
return beforeCall;
|
||||
}
|
||||
|
||||
public final int directJmp(long address, Register scratch) {
|
||||
int bytesToEmit = needsRex(scratch) ? 13 : 12;
|
||||
testAndAlign(bytesToEmit);
|
||||
int beforeJmp = position();
|
||||
movq(scratch, address);
|
||||
jmpWithoutAlignment(scratch);
|
||||
assert beforeJmp + bytesToEmit == position();
|
||||
return beforeJmp;
|
||||
}
|
||||
|
||||
// This should guarantee that the alignment in AMD64Assembler.jcc methods will be not triggered.
|
||||
private void alignFusedPair(Label branchTarget, boolean isShortJmp, int prevOpInBytes) {
|
||||
assert prevOpInBytes < 26 : "Fused pair may be longer than 0x20 bytes.";
|
||||
if (branchTarget == null) {
|
||||
testAndAlign(prevOpInBytes + 6);
|
||||
} else if (isShortJmp) {
|
||||
testAndAlign(prevOpInBytes + 2);
|
||||
} else if (!branchTarget.isBound()) {
|
||||
testAndAlign(prevOpInBytes + 6);
|
||||
} else {
|
||||
long disp = branchTarget.position() - (position() + prevOpInBytes);
|
||||
// assuming short jump first
|
||||
if (isByte(disp - 2)) {
|
||||
testAndAlign(prevOpInBytes + 2);
|
||||
// After alignment, isByte(disp - shortSize) might not hold. Need to check
|
||||
// again.
|
||||
disp = branchTarget.position() - (position() + prevOpInBytes);
|
||||
if (isByte(disp - 2)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
testAndAlign(prevOpInBytes + 6);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyMIOpAndJcc(AMD64MIOp op, OperandSize size, Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp, boolean annotateImm,
|
||||
IntConsumer applyBeforeFusedPair) {
|
||||
final int bytesToEmit = getPrefixInBytes(size, src, op.srcIsByte) + OPCODE_IN_BYTES + MODRM_IN_BYTES + op.immediateSize(size);
|
||||
alignFusedPair(branchTarget, isShortJmp, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
if (applyBeforeFusedPair != null) {
|
||||
applyBeforeFusedPair.accept(beforeFusedPair);
|
||||
}
|
||||
op.emit(this, size, src, imm32, annotateImm);
|
||||
assert beforeFusedPair + bytesToEmit == position();
|
||||
jcc(cc, branchTarget, isShortJmp);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
}
|
||||
|
||||
private void applyMIOpAndJcc(AMD64MIOp op, OperandSize size, AMD64Address src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp, boolean annotateImm,
|
||||
IntConsumer applyBeforeFusedPair) {
|
||||
final int bytesToEmit = getPrefixInBytes(size, src) + OPCODE_IN_BYTES + addressInBytes(src) + op.immediateSize(size);
|
||||
alignFusedPair(branchTarget, isShortJmp, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
if (applyBeforeFusedPair != null) {
|
||||
applyBeforeFusedPair.accept(beforeFusedPair);
|
||||
}
|
||||
op.emit(this, size, src, imm32, annotateImm);
|
||||
assert beforeFusedPair + bytesToEmit == position();
|
||||
jcc(cc, branchTarget, isShortJmp);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
}
|
||||
|
||||
private int applyRMOpAndJcc(AMD64RMOp op, OperandSize size, Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
final int bytesToEmit = getPrefixInBytes(size, src1, op.dstIsByte, src2, op.srcIsByte) + OPCODE_IN_BYTES + MODRM_IN_BYTES;
|
||||
alignFusedPair(branchTarget, isShortJmp, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
op.emit(this, size, src1, src2);
|
||||
final int beforeJcc = position();
|
||||
assert beforeFusedPair + bytesToEmit == beforeJcc;
|
||||
jcc(cc, branchTarget, isShortJmp);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
return beforeJcc;
|
||||
}
|
||||
|
||||
private int applyRMOpAndJcc(AMD64RMOp op, OperandSize size, Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp, IntConsumer applyBeforeFusedPair) {
|
||||
final int bytesToEmit = getPrefixInBytes(size, src1, op.dstIsByte, src2) + OPCODE_IN_BYTES + addressInBytes(src2);
|
||||
alignFusedPair(branchTarget, isShortJmp, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
if (applyBeforeFusedPair != null) {
|
||||
applyBeforeFusedPair.accept(beforeFusedPair);
|
||||
}
|
||||
op.emit(this, size, src1, src2);
|
||||
final int beforeJcc = position();
|
||||
assert beforeFusedPair + bytesToEmit == beforeJcc;
|
||||
jcc(cc, branchTarget, isShortJmp);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
return beforeJcc;
|
||||
}
|
||||
|
||||
public void applyMOpAndJcc(AMD64MOp op, OperandSize size, Register dst, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
final int bytesToEmit = getPrefixInBytes(size, dst, op.srcIsByte) + OPCODE_IN_BYTES + MODRM_IN_BYTES;
|
||||
alignFusedPair(branchTarget, isShortJmp, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
op.emit(this, size, dst);
|
||||
assert beforeFusedPair + bytesToEmit == position();
|
||||
jcc(cc, branchTarget, isShortJmp);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
}
|
||||
|
||||
public final void testAndJcc(OperandSize size, Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(AMD64MIOp.TEST, size, src, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void testlAndJcc(Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(AMD64MIOp.TEST, DWORD, src, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void testAndJcc(OperandSize size, AMD64Address src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp, IntConsumer applyBeforeFusedPair) {
|
||||
applyMIOpAndJcc(AMD64MIOp.TEST, size, src, imm32, cc, branchTarget, isShortJmp, false, applyBeforeFusedPair);
|
||||
}
|
||||
|
||||
public final void testAndJcc(OperandSize size, Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(AMD64RMOp.TEST, size, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void testlAndJcc(Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(AMD64RMOp.TEST, DWORD, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final int testqAndJcc(Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
return applyRMOpAndJcc(AMD64RMOp.TEST, QWORD, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void testAndJcc(OperandSize size, Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp, IntConsumer applyBeforeFusedPair) {
|
||||
applyRMOpAndJcc(AMD64RMOp.TEST, size, src1, src2, cc, branchTarget, isShortJmp, applyBeforeFusedPair);
|
||||
}
|
||||
|
||||
public final void testbAndJcc(Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(AMD64RMOp.TESTB, OperandSize.BYTE, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void testbAndJcc(Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(AMD64RMOp.TESTB, OperandSize.BYTE, src1, src2, cc, branchTarget, isShortJmp, null);
|
||||
}
|
||||
|
||||
public final void cmpAndJcc(OperandSize size, Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp, boolean annotateImm, IntConsumer applyBeforeFusedPair) {
|
||||
applyMIOpAndJcc(CMP.getMIOpcode(size, isByte(imm32)), size, src, imm32, cc, branchTarget, isShortJmp, annotateImm, applyBeforeFusedPair);
|
||||
}
|
||||
|
||||
public final void cmplAndJcc(Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(CMP.getMIOpcode(DWORD, isByte(imm32)), DWORD, src, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void cmpqAndJcc(Register src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(CMP.getMIOpcode(QWORD, isByte(imm32)), QWORD, src, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void cmpAndJcc(OperandSize size, AMD64Address src, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp, boolean annotateImm, IntConsumer applyBeforeFusedPair) {
|
||||
applyMIOpAndJcc(CMP.getMIOpcode(size, NumUtil.isByte(imm32)), size, src, imm32, cc, branchTarget, isShortJmp, annotateImm, applyBeforeFusedPair);
|
||||
}
|
||||
|
||||
public final void cmpAndJcc(OperandSize size, Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(CMP.getRMOpcode(size), size, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void cmplAndJcc(Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(CMP.getRMOpcode(DWORD), DWORD, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final int cmpqAndJcc(Register src1, Register src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
return applyRMOpAndJcc(CMP.getRMOpcode(QWORD), QWORD, src1, src2, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void cmpAndJcc(OperandSize size, Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp, IntConsumer applyBeforeFusedPair) {
|
||||
applyRMOpAndJcc(CMP.getRMOpcode(size), size, src1, src2, cc, branchTarget, isShortJmp, applyBeforeFusedPair);
|
||||
}
|
||||
|
||||
public final void cmplAndJcc(Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(CMP.getRMOpcode(DWORD), DWORD, src1, src2, cc, branchTarget, isShortJmp, null);
|
||||
}
|
||||
|
||||
public final int cmpqAndJcc(Register src1, AMD64Address src2, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
return applyRMOpAndJcc(CMP.getRMOpcode(QWORD), QWORD, src1, src2, cc, branchTarget, isShortJmp, null);
|
||||
}
|
||||
|
||||
public final void cmpAndJcc(OperandSize size, Register src1, Supplier<AMD64Address> src2, ConditionFlag cc, Label branchTarget) {
|
||||
AMD64Address placeHolder = getPlaceholder(position());
|
||||
final AMD64RMOp op = CMP.getRMOpcode(size);
|
||||
final int bytesToEmit = getPrefixInBytes(size, src1, op.dstIsByte, placeHolder) + OPCODE_IN_BYTES + addressInBytes(placeHolder);
|
||||
alignFusedPair(branchTarget, false, bytesToEmit);
|
||||
final int beforeFusedPair = position();
|
||||
AMD64Address src2AsAddress = src2.get();
|
||||
op.emit(this, size, src1, src2AsAddress);
|
||||
assert beforeFusedPair + bytesToEmit == position();
|
||||
jcc(cc, branchTarget, false);
|
||||
assert ensureWithinBoundary(beforeFusedPair);
|
||||
}
|
||||
|
||||
public final void andlAndJcc(Register dst, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(AND.getMIOpcode(DWORD, isByte(imm32)), DWORD, dst, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void addqAndJcc(Register dst, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(ADD.getMIOpcode(QWORD, isByte(imm32)), QWORD, dst, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void sublAndJcc(Register dst, Register src, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(SUB.getRMOpcode(DWORD), DWORD, dst, src, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void subqAndJcc(Register dst, Register src, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyRMOpAndJcc(SUB.getRMOpcode(QWORD), QWORD, dst, src, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void sublAndJcc(Register dst, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(SUB.getMIOpcode(DWORD, isByte(imm32)), DWORD, dst, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void subqAndJcc(Register dst, int imm32, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMIOpAndJcc(SUB.getMIOpcode(QWORD, isByte(imm32)), QWORD, dst, imm32, cc, branchTarget, isShortJmp, false, null);
|
||||
}
|
||||
|
||||
public final void incqAndJcc(Register dst, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMOpAndJcc(INC, QWORD, dst, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
|
||||
public final void decqAndJcc(Register dst, ConditionFlag cc, Label branchTarget, boolean isShortJmp) {
|
||||
applyMOpAndJcc(DEC, QWORD, dst, cc, branchTarget, isShortJmp);
|
||||
}
|
||||
}
|
||||
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.amd64;
|
||||
|
||||
import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.DWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.QWORD;
|
||||
import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.XMM;
|
||||
import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.YMM;
|
||||
import static org.graalvm.compiler.asm.amd64.AVXKind.AVXSize.ZMM;
|
||||
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
|
||||
/**
|
||||
* Helper methods for dealing with AVX and SSE {@link AMD64Kind AMD64Kinds}.
|
||||
*/
|
||||
public final class AVXKind {
|
||||
|
||||
public enum AVXSize {
|
||||
DWORD,
|
||||
QWORD,
|
||||
XMM,
|
||||
YMM,
|
||||
ZMM;
|
||||
|
||||
public int getBytes() {
|
||||
switch (this) {
|
||||
case DWORD:
|
||||
return 4;
|
||||
case QWORD:
|
||||
return 8;
|
||||
case XMM:
|
||||
return 16;
|
||||
case YMM:
|
||||
return 32;
|
||||
case ZMM:
|
||||
return 64;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AVXKind() {
|
||||
}
|
||||
|
||||
public static AVXSize getRegisterSize(Value a) {
|
||||
AMD64Kind kind = (AMD64Kind) a.getPlatformKind();
|
||||
if (kind.isXMM()) {
|
||||
return getRegisterSize(kind);
|
||||
} else {
|
||||
return XMM;
|
||||
}
|
||||
}
|
||||
|
||||
public static AVXSize getDataSize(AMD64Kind kind) {
|
||||
assert kind.isXMM() : "unexpected kind " + kind;
|
||||
switch (kind.getSizeInBytes()) {
|
||||
case 4:
|
||||
return DWORD;
|
||||
case 8:
|
||||
return QWORD;
|
||||
case 16:
|
||||
return XMM;
|
||||
case 32:
|
||||
return YMM;
|
||||
case 64:
|
||||
return ZMM;
|
||||
default:
|
||||
throw GraalError.shouldNotReachHere("unsupported kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
public static AVXSize getRegisterSize(AMD64Kind kind) {
|
||||
assert kind.isXMM() : "unexpected kind " + kind;
|
||||
int size = kind.getSizeInBytes();
|
||||
if (size > 32) {
|
||||
return ZMM;
|
||||
} else if (size > 16) {
|
||||
return YMM;
|
||||
} else {
|
||||
return XMM;
|
||||
}
|
||||
}
|
||||
|
||||
public static AMD64Kind changeSize(AMD64Kind kind, AVXSize newSize) {
|
||||
return getAVXKind(kind.getScalar(), newSize);
|
||||
}
|
||||
|
||||
public static AMD64Kind getMaskKind(AMD64Kind kind) {
|
||||
switch (kind.getScalar()) {
|
||||
case SINGLE:
|
||||
return getAVXKind(AMD64Kind.DWORD, kind.getVectorLength());
|
||||
case DOUBLE:
|
||||
return getAVXKind(AMD64Kind.QWORD, kind.getVectorLength());
|
||||
default:
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
public static AMD64Kind getAVXKind(AMD64Kind base, AVXSize size) {
|
||||
for (AMD64Kind ret : AMD64Kind.values()) {
|
||||
if (ret.getScalar() == base && ret.getSizeInBytes() == size.getBytes()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
throw GraalError.shouldNotReachHere(String.format("unsupported vector kind: %s x %s", size, base));
|
||||
}
|
||||
|
||||
public static AMD64Kind getAVXKind(AMD64Kind base, int length) {
|
||||
for (AMD64Kind ret : AMD64Kind.values()) {
|
||||
if (ret.getScalar() == base && ret.getVectorLength() == length) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
throw GraalError.shouldNotReachHere(String.format("unsupported vector kind: %d x %s", length, base));
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.test;
|
||||
|
||||
import static org.graalvm.compiler.core.common.CompilationRequestIdentifier.asCompilationRequest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.code.DisassemblerProvider;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
|
||||
import org.graalvm.compiler.core.gen.LIRGenerationProvider;
|
||||
import org.graalvm.compiler.core.target.Backend;
|
||||
import org.graalvm.compiler.debug.DebugContext;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.runtime.RuntimeProvider;
|
||||
import org.graalvm.compiler.serviceprovider.GraalServices;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Assert;
|
||||
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.code.CodeCacheProvider;
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.code.InvalidInstalledCodeException;
|
||||
import jdk.vm.ci.code.RegisterConfig;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import jdk.vm.ci.runtime.JVMCIBackend;
|
||||
|
||||
public abstract class AssemblerTest extends GraalTest {
|
||||
|
||||
private final MetaAccessProvider metaAccess;
|
||||
protected final CodeCacheProvider codeCache;
|
||||
private final Backend backend;
|
||||
|
||||
public interface CodeGenTest {
|
||||
byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the initial option values provided by the Graal runtime. These are option values
|
||||
* typically parsed from the command line.
|
||||
*/
|
||||
public static OptionValues getInitialOptions() {
|
||||
return Graal.getRequiredCapability(OptionValues.class);
|
||||
}
|
||||
|
||||
public AssemblerTest() {
|
||||
JVMCIBackend providers = JVMCI.getRuntime().getHostJVMCIBackend();
|
||||
this.metaAccess = providers.getMetaAccess();
|
||||
this.codeCache = providers.getCodeCache();
|
||||
this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
|
||||
}
|
||||
|
||||
public MetaAccessProvider getMetaAccess() {
|
||||
return metaAccess;
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
protected InstalledCode assembleMethod(Method m, CodeGenTest test) {
|
||||
ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(m);
|
||||
OptionValues options = getInitialOptions();
|
||||
DebugContext debug = getDebugContext(options);
|
||||
try (DebugContext.Scope s = debug.scope("assembleMethod", method, codeCache)) {
|
||||
RegisterConfig registerConfig = codeCache.getRegisterConfig();
|
||||
CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
|
||||
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build();
|
||||
RegisterAllocationConfig registerAllocationConfig = backend.newRegisterAllocationConfig(null, null);
|
||||
CallingConvention cc = ((LIRGenerationProvider) backend).newLIRGenerationResult(compilationId, null, registerAllocationConfig, graph, null).getCallingConvention();
|
||||
|
||||
CompilationResult compResult = new CompilationResult(graph.compilationId());
|
||||
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
|
||||
compResult.setTargetCode(targetCode, targetCode.length);
|
||||
compResult.setTotalFrameSize(0);
|
||||
compResult.close();
|
||||
|
||||
InstalledCode code = backend.addInstalledCode(debug, method, asCompilationRequest(compilationId), compResult);
|
||||
|
||||
for (DisassemblerProvider dis : GraalServices.load(DisassemblerProvider.class)) {
|
||||
String disasm1 = dis.disassembleCompiledCode(codeCache, compResult);
|
||||
Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0);
|
||||
String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code);
|
||||
Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0);
|
||||
}
|
||||
return code;
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object runTest(String methodName, CodeGenTest test, Object... args) {
|
||||
Method method = getMethod(methodName);
|
||||
InstalledCode code = assembleMethod(method, test);
|
||||
try {
|
||||
return code.executeVarargs(args);
|
||||
} catch (InvalidInstalledCodeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertReturn(String methodName, CodeGenTest test, Object expected, Object... args) {
|
||||
Object actual = runTest(methodName, test, args);
|
||||
Assert.assertEquals("unexpected return value", expected, actual);
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
/**
|
||||
* Abstract base class that represents a platform specific address.
|
||||
*/
|
||||
public abstract class AbstractAddress {
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
public class AsmOptions {
|
||||
|
||||
public static final int InitialCodeBufferSize = 232;
|
||||
}
|
||||
@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.StackSlot;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
/**
|
||||
* The platform-independent base class for the assembler.
|
||||
*/
|
||||
public abstract class Assembler {
|
||||
|
||||
public abstract static class CodeAnnotation {
|
||||
/**
|
||||
* The position (bytes from the beginning of the method) of the annotated instruction.
|
||||
*/
|
||||
public final int instructionPosition;
|
||||
|
||||
protected CodeAnnotation(int instructionStartPosition) {
|
||||
this.instructionPosition = instructionStartPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public final TargetDescription target;
|
||||
private List<LabelHint> jumpDisplacementHints;
|
||||
|
||||
/**
|
||||
* Labels with instructions to be patched when it is {@linkplain Label#bind bound}.
|
||||
*/
|
||||
Label labelsWithPatches;
|
||||
|
||||
/**
|
||||
* Backing code buffer.
|
||||
*/
|
||||
private final Buffer codeBuffer;
|
||||
|
||||
protected Consumer<CodeAnnotation> codePatchingAnnotationConsumer;
|
||||
|
||||
public Assembler(TargetDescription target) {
|
||||
this.target = target;
|
||||
this.codeBuffer = new Buffer(target.arch.getByteOrder());
|
||||
}
|
||||
|
||||
public void setCodePatchingAnnotationConsumer(Consumer<CodeAnnotation> codeAnnotationConsumer) {
|
||||
assert this.codePatchingAnnotationConsumer == null : "overwriting existing value";
|
||||
this.codePatchingAnnotationConsumer = codeAnnotationConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of the underlying code buffer.
|
||||
*
|
||||
* @return current position in code buffer
|
||||
*/
|
||||
public int position() {
|
||||
return codeBuffer.position();
|
||||
}
|
||||
|
||||
public final void emitByte(int x) {
|
||||
codeBuffer.emitByte(x);
|
||||
}
|
||||
|
||||
public final void emitShort(int x) {
|
||||
codeBuffer.emitShort(x);
|
||||
}
|
||||
|
||||
public final void emitInt(int x) {
|
||||
codeBuffer.emitInt(x);
|
||||
}
|
||||
|
||||
public final void emitLong(long x) {
|
||||
codeBuffer.emitLong(x);
|
||||
}
|
||||
|
||||
public final void emitByte(int b, int pos) {
|
||||
codeBuffer.emitByte(b, pos);
|
||||
}
|
||||
|
||||
public final void emitShort(int b, int pos) {
|
||||
codeBuffer.emitShort(b, pos);
|
||||
}
|
||||
|
||||
public final void emitInt(int b, int pos) {
|
||||
codeBuffer.emitInt(b, pos);
|
||||
}
|
||||
|
||||
public final void emitLong(long b, int pos) {
|
||||
codeBuffer.emitLong(b, pos);
|
||||
}
|
||||
|
||||
public final int getByte(int pos) {
|
||||
return codeBuffer.getByte(pos);
|
||||
}
|
||||
|
||||
public final int getShort(int pos) {
|
||||
return codeBuffer.getShort(pos);
|
||||
}
|
||||
|
||||
public final int getInt(int pos) {
|
||||
return codeBuffer.getInt(pos);
|
||||
}
|
||||
|
||||
private static final String NEWLINE = System.lineSeparator();
|
||||
|
||||
/**
|
||||
* Some GPU architectures have a text based encoding.
|
||||
*/
|
||||
public final void emitString(String x) {
|
||||
emitString0("\t"); // XXX REMOVE ME pretty-printing
|
||||
emitString0(x);
|
||||
emitString0(NEWLINE);
|
||||
}
|
||||
|
||||
// XXX for pretty-printing
|
||||
public final void emitString0(String x) {
|
||||
codeBuffer.emitBytes(x.getBytes(), 0, x.length());
|
||||
}
|
||||
|
||||
public void emitString(String s, int pos) {
|
||||
codeBuffer.emitBytes(s.getBytes(), pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this assembler. No extra data can be written to this assembler after this call.
|
||||
*
|
||||
* @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
|
||||
* including) {@code position()} is returned
|
||||
* @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
|
||||
*/
|
||||
public byte[] close(boolean trimmedCopy) {
|
||||
checkAndClearLabelsWithPatches();
|
||||
return codeBuffer.close(trimmedCopy);
|
||||
}
|
||||
|
||||
public byte[] copy(int start, int end) {
|
||||
return codeBuffer.copyData(start, end);
|
||||
}
|
||||
|
||||
private void checkAndClearLabelsWithPatches() throws InternalError {
|
||||
Label label = labelsWithPatches;
|
||||
while (label != null) {
|
||||
if (label.patchPositions != null) {
|
||||
throw new GraalError("Label used by instructions at following offsets has not been bound: %s", label.patchPositions);
|
||||
}
|
||||
Label next = label.nextWithPatches;
|
||||
label.nextWithPatches = null;
|
||||
label = next;
|
||||
}
|
||||
labelsWithPatches = null;
|
||||
}
|
||||
|
||||
public void bind(Label l) {
|
||||
assert !l.isBound() : "can bind label only once";
|
||||
l.bind(position(), this);
|
||||
}
|
||||
|
||||
public abstract void align(int modulus);
|
||||
|
||||
public abstract void jmp(Label l);
|
||||
|
||||
protected abstract void patchJumpTarget(int branch, int jumpTarget);
|
||||
|
||||
private Map<Label, String> nameMap;
|
||||
|
||||
/**
|
||||
* Creates a name for a label.
|
||||
*
|
||||
* @param l the label for which a name is being created
|
||||
* @param id a label identifier that is unique with the scope of this assembler
|
||||
* @return a label name in the form of "L123"
|
||||
*/
|
||||
protected String createLabelName(Label l, int id) {
|
||||
return "L" + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a name for a label, creating it if it does not yet exist. By default, the returned name
|
||||
* is only unique with the scope of this assembler.
|
||||
*/
|
||||
public String nameOf(Label l) {
|
||||
if (nameMap == null) {
|
||||
nameMap = new HashMap<>();
|
||||
}
|
||||
String name = nameMap.get(l);
|
||||
if (name == null) {
|
||||
name = createLabelName(l, nameMap.size());
|
||||
nameMap.put(l, name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an
|
||||
* {@link AbstractAddress}.
|
||||
*/
|
||||
public abstract AbstractAddress makeAddress(Register base, int displacement);
|
||||
|
||||
/**
|
||||
* Returns a target specific placeholder address that can be used for code patching.
|
||||
*
|
||||
* @param instructionStartPosition The start of the instruction, i.e., the value that is used as
|
||||
* the key for looking up placeholder patching information.
|
||||
*/
|
||||
public abstract AbstractAddress getPlaceholder(int instructionStartPosition);
|
||||
|
||||
/**
|
||||
* Emits a NOP instruction to advance the current PC.
|
||||
*/
|
||||
public abstract void ensureUniquePC();
|
||||
|
||||
public void reset() {
|
||||
codeBuffer.reset();
|
||||
captureLabelPositions();
|
||||
}
|
||||
|
||||
private void captureLabelPositions() {
|
||||
if (jumpDisplacementHints == null) {
|
||||
return;
|
||||
}
|
||||
for (LabelHint request : this.jumpDisplacementHints) {
|
||||
request.capture();
|
||||
}
|
||||
}
|
||||
|
||||
public LabelHint requestLabelHint(Label label) {
|
||||
if (jumpDisplacementHints == null) {
|
||||
jumpDisplacementHints = new ArrayList<>();
|
||||
}
|
||||
LabelHint hint = new LabelHint(label, position());
|
||||
this.jumpDisplacementHints.add(hint);
|
||||
return hint;
|
||||
}
|
||||
|
||||
public InstructionCounter getInstructionCounter() {
|
||||
throw new UnsupportedOperationException("Instruction counter is not implemented for " + this);
|
||||
}
|
||||
|
||||
public static class LabelHint {
|
||||
private Label label;
|
||||
private int forPosition;
|
||||
private int capturedTarget = -1;
|
||||
|
||||
protected LabelHint(Label label, int lastPosition) {
|
||||
super();
|
||||
this.label = label;
|
||||
this.forPosition = lastPosition;
|
||||
}
|
||||
|
||||
protected void capture() {
|
||||
this.capturedTarget = label.position();
|
||||
}
|
||||
|
||||
public int getTarget() {
|
||||
assert isValid();
|
||||
return capturedTarget;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
assert isValid();
|
||||
return forPosition;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return capturedTarget >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruction counter class which gives the user of the assembler to count different kinds of
|
||||
* instructions in the generated assembler code.
|
||||
*/
|
||||
public interface InstructionCounter {
|
||||
String[] getSupportedInstructionTypes();
|
||||
|
||||
int[] countInstructions(String[] instructionTypes, int beginPc, int endPc);
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
import org.graalvm.compiler.core.common.GraalBailoutException;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BranchTargetOutOfBoundsException extends GraalBailoutException {
|
||||
|
||||
public BranchTargetOutOfBoundsException(boolean permanent, String format, Object... args) {
|
||||
super(permanent, format, args);
|
||||
}
|
||||
|
||||
public BranchTargetOutOfBoundsException(String format, Object... args) {
|
||||
super(format, args);
|
||||
}
|
||||
|
||||
public BranchTargetOutOfBoundsException(Throwable cause, String format, Object... args) {
|
||||
super(cause, format, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.serviceprovider.BufferUtil;
|
||||
|
||||
/**
|
||||
* Code buffer management for the assembler.
|
||||
*/
|
||||
final class Buffer {
|
||||
|
||||
protected ByteBuffer data;
|
||||
|
||||
Buffer(ByteOrder order) {
|
||||
data = ByteBuffer.allocate(AsmOptions.InitialCodeBufferSize);
|
||||
data.order(order);
|
||||
}
|
||||
|
||||
public int position() {
|
||||
return data.position();
|
||||
}
|
||||
|
||||
public void setPosition(int position) {
|
||||
assert position >= 0 && position <= data.limit();
|
||||
BufferUtil.asBaseBuffer(data).position(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this buffer. Any further operations on a closed buffer will result in a
|
||||
* {@link NullPointerException}.
|
||||
*
|
||||
* @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
|
||||
* including) {@code position()} is returned
|
||||
* @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
|
||||
*/
|
||||
public byte[] close(boolean trimmedCopy) {
|
||||
byte[] result = data.array();
|
||||
if (trimmedCopy) {
|
||||
// Make a copy even if result.length == data.position() since
|
||||
// the API for trimmedCopy states a copy is always made
|
||||
result = Arrays.copyOf(result, data.position());
|
||||
}
|
||||
data = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] copyData(int start, int end) {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.copyOfRange(data.array(), start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the data from this buffer into a given array.
|
||||
*
|
||||
* @param dst the destination array
|
||||
* @param off starting position in {@code dst}
|
||||
* @param len number of bytes to copy
|
||||
*/
|
||||
public void copyInto(byte[] dst, int off, int len) {
|
||||
System.arraycopy(data.array(), 0, dst, off, len);
|
||||
}
|
||||
|
||||
protected void ensureSize(int length) {
|
||||
if (length >= data.limit()) {
|
||||
byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
|
||||
ByteBuffer newData = ByteBuffer.wrap(newBuf);
|
||||
newData.order(data.order());
|
||||
BufferUtil.asBaseBuffer(newData).position(data.position());
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
public void emitBytes(byte[] arr, int off, int len) {
|
||||
ensureSize(data.position() + len);
|
||||
data.put(arr, off, len);
|
||||
}
|
||||
|
||||
public void emitByte(int b) {
|
||||
assert NumUtil.isUByte(b) || NumUtil.isByte(b);
|
||||
ensureSize(data.position() + 1);
|
||||
data.put((byte) (b & 0xFF));
|
||||
}
|
||||
|
||||
public void emitShort(int b) {
|
||||
assert NumUtil.isUShort(b) || NumUtil.isShort(b);
|
||||
ensureSize(data.position() + 2);
|
||||
data.putShort((short) b);
|
||||
}
|
||||
|
||||
public void emitInt(int b) {
|
||||
ensureSize(data.position() + 4);
|
||||
data.putInt(b);
|
||||
}
|
||||
|
||||
public void emitLong(long b) {
|
||||
ensureSize(data.position() + 8);
|
||||
data.putLong(b);
|
||||
}
|
||||
|
||||
public void emitBytes(byte[] arr, int pos) {
|
||||
final int len = arr.length;
|
||||
ensureSize(pos + len);
|
||||
// Write directly into the underlying array so as to not
|
||||
// change the ByteBuffer's position
|
||||
System.arraycopy(arr, 0, data.array(), pos, len);
|
||||
}
|
||||
|
||||
public void emitByte(int b, int pos) {
|
||||
assert NumUtil.isUByte(b) || NumUtil.isByte(b);
|
||||
ensureSize(pos + 1);
|
||||
data.put(pos, (byte) (b & 0xFF));
|
||||
}
|
||||
|
||||
public void emitShort(int b, int pos) {
|
||||
assert NumUtil.isUShort(b) || NumUtil.isShort(b);
|
||||
ensureSize(pos + 2);
|
||||
data.putShort(pos, (short) b).position();
|
||||
}
|
||||
|
||||
public void emitInt(int b, int pos) {
|
||||
ensureSize(pos + 4);
|
||||
data.putInt(pos, b).position();
|
||||
}
|
||||
|
||||
public void emitLong(long b, int pos) {
|
||||
ensureSize(pos + 8);
|
||||
data.putLong(pos, b).position();
|
||||
}
|
||||
|
||||
public int getByte(int pos) {
|
||||
int b = data.get(pos);
|
||||
return b & 0xff;
|
||||
}
|
||||
|
||||
public int getShort(int pos) {
|
||||
short s = data.getShort(pos);
|
||||
return s & 0xffff;
|
||||
}
|
||||
|
||||
public int getInt(int pos) {
|
||||
return data.getInt(pos);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
BufferUtil.asBaseBuffer(data).clear();
|
||||
}
|
||||
}
|
||||
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
|
||||
/**
|
||||
* This class represents a label within assembly code.
|
||||
*/
|
||||
public final class Label {
|
||||
|
||||
private int position = -1;
|
||||
private int blockId = -1;
|
||||
|
||||
/**
|
||||
* Positions of instructions that jump to this unresolved label. These instructions are patched
|
||||
* when the label is bound.
|
||||
*/
|
||||
ArrayList<Integer> patchPositions;
|
||||
|
||||
/**
|
||||
* Link in list of labels with instructions to be patched.
|
||||
*/
|
||||
Label nextWithPatches;
|
||||
|
||||
/**
|
||||
* Returns the position of this label in the code buffer.
|
||||
*
|
||||
* @return the position
|
||||
*/
|
||||
public int position() {
|
||||
assert position >= 0 : "Unbound label is being referenced";
|
||||
return position;
|
||||
}
|
||||
|
||||
public Label() {
|
||||
}
|
||||
|
||||
public Label(int id) {
|
||||
blockId = id;
|
||||
}
|
||||
|
||||
public int getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the label to {@code pos} and patches all instructions added by
|
||||
* {@link #addPatchAt(int, Assembler)}.
|
||||
*/
|
||||
protected void bind(int pos, Assembler asm) {
|
||||
if (pos < 0) {
|
||||
throw new GraalError("Cannot bind label to negative position %d", pos);
|
||||
}
|
||||
this.position = pos;
|
||||
if (patchPositions != null) {
|
||||
for (int i = 0; i < patchPositions.size(); ++i) {
|
||||
asm.patchJumpTarget(patchPositions.get(i), position);
|
||||
}
|
||||
patchPositions = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
return position >= 0;
|
||||
}
|
||||
|
||||
public void addPatchAt(int branchLocation, Assembler asm) {
|
||||
assert !isBound() : "Label is already bound " + this + " " + branchLocation + " at position " + position;
|
||||
if (patchPositions == null) {
|
||||
patchPositions = new ArrayList<>(2);
|
||||
nextWithPatches = asm.labelsWithPatches;
|
||||
asm.labelsWithPatches = this;
|
||||
}
|
||||
patchPositions.add(branchLocation);
|
||||
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
if (this.patchPositions != null) {
|
||||
this.patchPositions.clear();
|
||||
}
|
||||
this.position = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return isBound() ? String.valueOf(position()) : "?";
|
||||
}
|
||||
}
|
||||
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.bytecode;
|
||||
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import jdk.vm.ci.meta.ConstantPool;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/**
|
||||
* Utilities for working around the absence of method annotations and parameter annotations on
|
||||
* bridge methods where the bridged methods have method annotations or parameter annotations. Not
|
||||
* all Java compilers copy method annotations and parameter annotations to bridge methods.
|
||||
*
|
||||
* @see <a href="http://bugs.java.com/view_bug.do?bug_id=6695379">6695379</a>
|
||||
* @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=495396">495396</a>
|
||||
* @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=427745">427745</a>
|
||||
*/
|
||||
public class BridgeMethodUtils {
|
||||
|
||||
/**
|
||||
* Gets the method bridged to by a {@linkplain ResolvedJavaMethod#isBridge() bridge} method. The
|
||||
* value returned is the method called by {@code method} that has the same name as
|
||||
* {@code bridge}.
|
||||
*
|
||||
* @param bridge a bridge method
|
||||
* @return the method called by {@code bridge} whose name is the same as
|
||||
* {@code bridge.getName()}
|
||||
*/
|
||||
public static ResolvedJavaMethod getBridgedMethod(ResolvedJavaMethod bridge) {
|
||||
assert bridge.isBridge();
|
||||
Bytecode code = new ResolvedJavaMethodBytecode(bridge);
|
||||
BytecodeStream stream = new BytecodeStream(code.getCode());
|
||||
int opcode = stream.currentBC();
|
||||
ResolvedJavaMethod bridged = null;
|
||||
boolean calledAbstractMethodErrorConstructor = false;
|
||||
while (opcode != Bytecodes.END) {
|
||||
switch (opcode) {
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKESPECIAL:
|
||||
case INVOKESTATIC:
|
||||
case INVOKEINTERFACE: {
|
||||
int cpi = stream.readCPI();
|
||||
ConstantPool cp = code.getConstantPool();
|
||||
cp.loadReferencedType(cpi, opcode);
|
||||
ResolvedJavaMethod method = (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode);
|
||||
if (method.getName().equals(bridge.getName())) {
|
||||
if (!assertionsEnabled()) {
|
||||
return method;
|
||||
}
|
||||
assert bridged == null || bridged.equals(method) : String.format("Found calls to different methods named %s in bridge method %s%n callee 1: %s%n callee 2: %s",
|
||||
bridge.getName(), bridge.format("%R %H.%n(%P)"), bridged.format("%R %H.%n(%P)"), method.format("%R %H.%n(%P)"));
|
||||
bridged = method;
|
||||
} else if (method.getName().equals("<init>") && method.getDeclaringClass().getName().equals("Ljava/lang/AbstractMethodError;")) {
|
||||
calledAbstractMethodErrorConstructor = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATHROW: {
|
||||
if (calledAbstractMethodErrorConstructor) {
|
||||
// This is a miranda method
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
if (bridged == null) {
|
||||
String dis = new BytecodeDisassembler().disassemble(bridge);
|
||||
throw new InternalError(String.format("Couldn't find method bridged by %s:%n%s", bridge.format("%R %H.%n(%P)"), dis));
|
||||
}
|
||||
return bridged;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static boolean assertionsEnabled() {
|
||||
boolean enabled = false;
|
||||
assert enabled = true;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for {@link ResolvedJavaMethod#getAnnotation(Class)} that handles the absence of
|
||||
* annotations on bridge methods where the bridged method has annotations.
|
||||
*/
|
||||
public static <T extends Annotation> T getAnnotation(Class<T> annotationClass, ResolvedJavaMethod method) {
|
||||
T a = method.getAnnotation(annotationClass);
|
||||
if (a == null && method.isBridge()) {
|
||||
ResolvedJavaMethod bridged = getBridgedMethod(method);
|
||||
if (bridged != null) {
|
||||
a = bridged.getAnnotation(annotationClass);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for {@link ResolvedJavaMethod#getAnnotations()} that handles the absence of
|
||||
* annotations on bridge methods where the bridged method has annotations.
|
||||
*/
|
||||
public static Annotation[] getAnnotations(ResolvedJavaMethod method) {
|
||||
Annotation[] a = method.getAnnotations();
|
||||
if (a.length == 0 && method.isBridge()) {
|
||||
ResolvedJavaMethod bridged = getBridgedMethod(method);
|
||||
if (bridged != null) {
|
||||
a = bridged.getAnnotations();
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for {@link ResolvedJavaMethod#getDeclaredAnnotations()} that handles the absence of
|
||||
* annotations on bridge methods where the bridged method has annotations.
|
||||
*/
|
||||
public static Annotation[] getDeclaredAnnotations(ResolvedJavaMethod method) {
|
||||
Annotation[] a = method.getAnnotations();
|
||||
if (a.length == 0 && method.isBridge()) {
|
||||
ResolvedJavaMethod bridged = getBridgedMethod(method);
|
||||
if (bridged != null) {
|
||||
a = bridged.getDeclaredAnnotations();
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for {@link ResolvedJavaMethod#getParameterAnnotations()} that handles the absence of
|
||||
* parameter annotations on bridge methods where the bridged method has parameter annotations.
|
||||
*/
|
||||
public static Annotation[][] getParameterAnnotations(ResolvedJavaMethod method) {
|
||||
Annotation[][] a = method.getParameterAnnotations();
|
||||
if (a.length == 0 && method.isBridge()) {
|
||||
ResolvedJavaMethod bridged = getBridgedMethod(method);
|
||||
if (bridged != null) {
|
||||
a = bridged.getParameterAnnotations();
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for {@link ResolvedJavaMethod#getParameterAnnotation(Class, int)} that handles the
|
||||
* absence of parameter annotations on bridge methods where the bridged method has parameter
|
||||
* annotations.
|
||||
*/
|
||||
public static <T extends Annotation> T getParameterAnnotation(Class<T> annotationClass, int parameterIndex, ResolvedJavaMethod method) {
|
||||
T a = method.getParameterAnnotation(annotationClass, parameterIndex);
|
||||
if (a == null && method.isBridge()) {
|
||||
ResolvedJavaMethod bridged = getBridgedMethod(method);
|
||||
if (bridged != null) {
|
||||
a = bridged.getParameterAnnotation(annotationClass, parameterIndex);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.bytecode;
|
||||
|
||||
import jdk.vm.ci.meta.ConstantPool;
|
||||
import jdk.vm.ci.meta.ExceptionHandler;
|
||||
import jdk.vm.ci.meta.LineNumberTable;
|
||||
import jdk.vm.ci.meta.LocalVariableTable;
|
||||
import jdk.vm.ci.meta.ProfilingInfo;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/**
|
||||
* An interface for accessing the bytecode properties of a {@link ResolvedJavaMethod} that allows
|
||||
* for different properties than those returned by {@link ResolvedJavaMethod}. Since the bytecode
|
||||
* accessed directly from {@link ResolvedJavaMethod} may have been subject to bytecode
|
||||
* instrumentation and VM rewriting, this indirection can be used to enable access to the original
|
||||
* bytecode of a method (i.e., as defined in a class file).
|
||||
*/
|
||||
public interface Bytecode {
|
||||
|
||||
/**
|
||||
* Gets the method this object supplies bytecode for.
|
||||
*/
|
||||
ResolvedJavaMethod getMethod();
|
||||
|
||||
byte[] getCode();
|
||||
|
||||
int getCodeSize();
|
||||
|
||||
int getMaxStackSize();
|
||||
|
||||
int getMaxLocals();
|
||||
|
||||
ConstantPool getConstantPool();
|
||||
|
||||
LineNumberTable getLineNumberTable();
|
||||
|
||||
LocalVariableTable getLocalVariableTable();
|
||||
|
||||
StackTraceElement asStackTraceElement(int bci);
|
||||
|
||||
ProfilingInfo getProfilingInfo();
|
||||
|
||||
ExceptionHandler[] getExceptionHandlers();
|
||||
|
||||
/**
|
||||
* Gets the {@link BytecodeProvider} from which this object was acquired.
|
||||
*/
|
||||
BytecodeProvider getOrigin();
|
||||
|
||||
static String toLocation(Bytecode bytecode, int bci) {
|
||||
return appendLocation(new StringBuilder(), bytecode, bci).toString();
|
||||
}
|
||||
|
||||
static StringBuilder appendLocation(StringBuilder sb, Bytecode bytecode, int bci) {
|
||||
if (bytecode != null) {
|
||||
StackTraceElement ste = bytecode.asStackTraceElement(bci);
|
||||
if (ste.getFileName() != null && ste.getLineNumber() > 0) {
|
||||
sb.append(ste);
|
||||
} else {
|
||||
sb.append(bytecode.getMethod().format("%H.%n(%p)"));
|
||||
}
|
||||
} else {
|
||||
sb.append("Null method");
|
||||
}
|
||||
return sb.append(" [bci: ").append(bci).append(']');
|
||||
}
|
||||
}
|
||||
@ -1,383 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.bytecode;
|
||||
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.GOTO;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFLE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFLT;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFNE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INSTANCEOF;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LDC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.NEW;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.NEWARRAY;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.RET;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
|
||||
|
||||
import jdk.vm.ci.meta.ConstantPool;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaField;
|
||||
import jdk.vm.ci.meta.JavaMethod;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/**
|
||||
* Utility for producing a {@code javap}-like disassembly of bytecode.
|
||||
*/
|
||||
public class BytecodeDisassembler {
|
||||
|
||||
/**
|
||||
* Specifies if the disassembly for a single instruction can span multiple lines.
|
||||
*/
|
||||
private final boolean multiline;
|
||||
|
||||
private final boolean newLine;
|
||||
|
||||
public BytecodeDisassembler(boolean multiline, boolean newLine) {
|
||||
this.multiline = multiline;
|
||||
this.newLine = newLine;
|
||||
}
|
||||
|
||||
public BytecodeDisassembler(boolean multiline) {
|
||||
this(multiline, true);
|
||||
}
|
||||
|
||||
public BytecodeDisassembler() {
|
||||
this(true, true);
|
||||
}
|
||||
|
||||
public static String disassembleOne(ResolvedJavaMethod method, int bci) {
|
||||
return new BytecodeDisassembler(false, false).disassemble(method, bci, bci);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassembles the bytecode of a given method in a {@code javap}-like format.
|
||||
*
|
||||
* @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
|
||||
*/
|
||||
public String disassemble(ResolvedJavaMethod method) {
|
||||
return disassemble(method, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassembles the bytecode of a given method in a {@code javap}-like format.
|
||||
*
|
||||
* @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
|
||||
*/
|
||||
public String disassemble(ResolvedJavaMethod method, int startBci, int endBci) {
|
||||
return disassemble(new ResolvedJavaMethodBytecode(method), startBci, endBci);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassembles {@code code} in a {@code javap}-like format.
|
||||
*/
|
||||
public String disassemble(Bytecode code) {
|
||||
return disassemble(code, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassembles {@code code} in a {@code javap}-like format.
|
||||
*/
|
||||
public String disassemble(Bytecode code, int startBci, int endBci) {
|
||||
if (code.getCode() == null) {
|
||||
return null;
|
||||
}
|
||||
ResolvedJavaMethod method = code.getMethod();
|
||||
ConstantPool cp = code.getConstantPool();
|
||||
BytecodeStream stream = new BytecodeStream(code.getCode());
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int opcode = stream.currentBC();
|
||||
try {
|
||||
while (opcode != Bytecodes.END) {
|
||||
int bci = stream.currentBCI();
|
||||
if (bci >= startBci && bci <= endBci) {
|
||||
String mnemonic = Bytecodes.nameOf(opcode);
|
||||
buf.append(String.format("%4d: %-14s", bci, mnemonic));
|
||||
if (stream.nextBCI() > bci + 1) {
|
||||
decodeOperand(buf, stream, cp, method, bci, opcode);
|
||||
}
|
||||
if (newLine) {
|
||||
buf.append(String.format("%n"));
|
||||
}
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(String.format("Error disassembling %s%nPartial disassembly:%n%s", method.format("%H.%n(%p)"), buf.toString()), e);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void decodeOperand(StringBuilder buf, BytecodeStream stream, ConstantPool cp, ResolvedJavaMethod method, int bci, int opcode) {
|
||||
// @formatter:off
|
||||
switch (opcode) {
|
||||
case BIPUSH : buf.append(stream.readByte()); break;
|
||||
case SIPUSH : buf.append(stream.readShort()); break;
|
||||
case NEW :
|
||||
case CHECKCAST :
|
||||
case INSTANCEOF :
|
||||
case ANEWARRAY : {
|
||||
int cpi = stream.readCPI();
|
||||
JavaType type = cp.lookupType(cpi, opcode);
|
||||
buf.append(String.format("#%-10d // %s", cpi, type.toJavaName()));
|
||||
break;
|
||||
}
|
||||
case GETSTATIC :
|
||||
case PUTSTATIC :
|
||||
case GETFIELD :
|
||||
case PUTFIELD : {
|
||||
int cpi = stream.readCPI();
|
||||
JavaField field = cp.lookupField(cpi, method, opcode);
|
||||
String fieldDesc = field.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? field.format("%n:%T") : field.format("%H.%n:%T");
|
||||
buf.append(String.format("#%-10d // %s", cpi, fieldDesc));
|
||||
break;
|
||||
}
|
||||
case INVOKEVIRTUAL :
|
||||
case INVOKESPECIAL :
|
||||
case INVOKESTATIC : {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
|
||||
buf.append(String.format("#%-10d // %s", cpi, calleeDesc));
|
||||
break;
|
||||
}
|
||||
case INVOKEINTERFACE: {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
|
||||
buf.append(String.format("#%-10s // %s", cpi + ", " + stream.readUByte(bci + 3), calleeDesc));
|
||||
break;
|
||||
}
|
||||
case INVOKEDYNAMIC: {
|
||||
int cpi = stream.readCPI4();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? callee.format("%n:(%P)%R") : callee.format("%H.%n:(%P)%R");
|
||||
buf.append(String.format("#%-10d // %s", cpi, calleeDesc));
|
||||
break;
|
||||
}
|
||||
case LDC :
|
||||
case LDC_W :
|
||||
case LDC2_W : {
|
||||
int cpi = stream.readCPI();
|
||||
Object constant = cp.lookupConstant(cpi);
|
||||
String desc = null;
|
||||
if (constant instanceof JavaConstant) {
|
||||
JavaConstant c = ((JavaConstant) constant);
|
||||
desc = c.toValueString();
|
||||
} else {
|
||||
desc = constant.toString();
|
||||
}
|
||||
if (!multiline) {
|
||||
desc = desc.replaceAll("\\n", "");
|
||||
}
|
||||
buf.append(String.format("#%-10d // %s", cpi, desc));
|
||||
break;
|
||||
}
|
||||
case RET :
|
||||
case ILOAD :
|
||||
case LLOAD :
|
||||
case FLOAD :
|
||||
case DLOAD :
|
||||
case ALOAD :
|
||||
case ISTORE :
|
||||
case LSTORE :
|
||||
case FSTORE :
|
||||
case DSTORE :
|
||||
case ASTORE : {
|
||||
buf.append(String.format("%d", stream.readLocalIndex()));
|
||||
break;
|
||||
}
|
||||
case IFEQ :
|
||||
case IFNE :
|
||||
case IFLT :
|
||||
case IFGE :
|
||||
case IFGT :
|
||||
case IFLE :
|
||||
case IF_ICMPEQ :
|
||||
case IF_ICMPNE :
|
||||
case IF_ICMPLT :
|
||||
case IF_ICMPGE :
|
||||
case IF_ICMPGT :
|
||||
case IF_ICMPLE :
|
||||
case IF_ACMPEQ :
|
||||
case IF_ACMPNE :
|
||||
case GOTO :
|
||||
case JSR :
|
||||
case IFNULL :
|
||||
case IFNONNULL :
|
||||
case GOTO_W :
|
||||
case JSR_W : {
|
||||
buf.append(String.format("%d", stream.readBranchDest()));
|
||||
break;
|
||||
}
|
||||
case LOOKUPSWITCH :
|
||||
case TABLESWITCH : {
|
||||
BytecodeSwitch bswitch = opcode == LOOKUPSWITCH ? new BytecodeLookupSwitch(stream, bci) : new BytecodeTableSwitch(stream, bci);
|
||||
if (multiline) {
|
||||
buf.append("{ // " + bswitch.numberOfCases());
|
||||
for (int i = 0; i < bswitch.numberOfCases(); i++) {
|
||||
buf.append(String.format("%n %7d: %d", bswitch.keyAt(i), bswitch.targetAt(i)));
|
||||
}
|
||||
buf.append(String.format("%n default: %d", bswitch.defaultTarget()));
|
||||
buf.append(String.format("%n }"));
|
||||
} else {
|
||||
buf.append("[" + bswitch.numberOfCases()).append("] {");
|
||||
for (int i = 0; i < bswitch.numberOfCases(); i++) {
|
||||
buf.append(String.format("%d: %d", bswitch.keyAt(i), bswitch.targetAt(i)));
|
||||
if (i != bswitch.numberOfCases() - 1) {
|
||||
buf.append(", ");
|
||||
}
|
||||
}
|
||||
buf.append(String.format("} default: %d", bswitch.defaultTarget()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NEWARRAY : {
|
||||
int typecode = stream.readLocalIndex();
|
||||
// Checkstyle: stop
|
||||
switch (typecode) {
|
||||
case 4: buf.append("boolean"); break;
|
||||
case 5: buf.append("char"); break;
|
||||
case 6: buf.append("float"); break;
|
||||
case 7: buf.append("double"); break;
|
||||
case 8: buf.append("byte"); break;
|
||||
case 9: buf.append("short"); break;
|
||||
case 10: buf.append("int"); break;
|
||||
case 11: buf.append("long"); break;
|
||||
}
|
||||
// Checkstyle: resume
|
||||
|
||||
break;
|
||||
}
|
||||
case MULTIANEWARRAY : {
|
||||
int cpi = stream.readCPI();
|
||||
JavaType type = cp.lookupType(cpi, opcode);
|
||||
buf.append(String.format("#%-10s // %s", cpi + ", " + stream.readUByte(bci + 3), type.toJavaName()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static JavaMethod getInvokedMethodAt(ResolvedJavaMethod method, int invokeBci) {
|
||||
if (method.getCode() == null) {
|
||||
return null;
|
||||
}
|
||||
ConstantPool cp = method.getConstantPool();
|
||||
BytecodeStream stream = new BytecodeStream(method.getCode());
|
||||
int opcode = stream.currentBC();
|
||||
while (opcode != Bytecodes.END) {
|
||||
int bci = stream.currentBCI();
|
||||
if (bci == invokeBci) {
|
||||
if (stream.nextBCI() > bci + 1) {
|
||||
switch (opcode) {
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKESPECIAL:
|
||||
case INVOKESTATIC: {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
case INVOKEINTERFACE: {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
case INVOKEDYNAMIC: {
|
||||
int cpi = stream.readCPI4();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
default:
|
||||
throw new InternalError(BytecodeDisassembler.disassembleOne(method, invokeBci));
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getBytecodeAt(ResolvedJavaMethod method, int invokeBci) {
|
||||
if (method.getCode() == null) {
|
||||
return -1;
|
||||
}
|
||||
BytecodeStream stream = new BytecodeStream(method.getCode());
|
||||
int opcode = stream.currentBC();
|
||||
while (opcode != Bytecodes.END) {
|
||||
int bci = stream.currentBCI();
|
||||
if (bci == invokeBci) {
|
||||
return opcode;
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.bytecode;
|
||||
|
||||
/**
|
||||
* A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes.
|
||||
*/
|
||||
public class BytecodeLookupSwitch extends BytecodeSwitch {
|
||||
|
||||
private static final int OFFSET_TO_NUMBER_PAIRS = 4;
|
||||
private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8;
|
||||
private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12;
|
||||
private static final int PAIR_SIZE = 8;
|
||||
|
||||
/**
|
||||
* Constructor for a {@link BytecodeStream}.
|
||||
*
|
||||
* @param stream the {@code BytecodeStream} containing the switch instruction
|
||||
* @param bci the index in the stream of the switch instruction
|
||||
*/
|
||||
public BytecodeLookupSwitch(BytecodeStream stream, int bci) {
|
||||
super(stream, bci);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int offsetAt(int i) {
|
||||
return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_OFFSET + PAIR_SIZE * i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int keyAt(int i) {
|
||||
return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfCases() {
|
||||
return stream.readInt(alignedBci + OFFSET_TO_NUMBER_PAIRS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * numberOfCases() - bci;
|
||||
}
|
||||
}
|
||||
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