8264806: Remove the experimental JIT compiler

Reviewed-by: iignatyev, erikj
This commit is contained in:
Vladimir Kozlov 2021-04-27 06:23:21 +00:00
parent 7db9330c58
commit 4785e112ae
2884 changed files with 14 additions and 441532 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)"

View File

@ -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)
])

View File

@ -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

View File

@ -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=""

View File

@ -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@

View File

@ -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)

View File

@ -46,6 +46,4 @@ LANGTOOLS_MODULES= \
HOTSPOT_MODULES= \
jdk.hotspot.agent \
jdk.internal.vm.ci \
jdk.internal.vm.compiler \
jdk.internal.vm.compiler.management \
#

View File

@ -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))
};

View File

@ -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= \

View File

@ -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)) \

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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)})");
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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());
}
}

View File

@ -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);
}
};
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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,
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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&lt;Kind&gt;Snippet verifies that dead code elimination is prevented by the
* blackhole directive.
* <li>&lt;kind&gt;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());
}
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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&lt;Kind&gt;Snippet verifies that constant folding is prevented by the opaque
* directive.
* <li>&lt;kind&gt;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());
}
}
}

View File

@ -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();
}
}

View File

@ -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 &gt; 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) {
}
}

View File

@ -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;
}

View File

@ -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 {
}
}

View File

@ -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>
* &#64;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>
* &#64;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;
}

View File

@ -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 {
}
}

View File

@ -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);
}

View File

@ -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 {
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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()) : "?";
}
}

View File

@ -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;
}
}

View File

@ -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(']');
}
}

View File

@ -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;
}
}

View File

@ -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